Czy w C # istnieje odpowiednik typedef, czy jakoś uzyskać podobne zachowanie? Zrobiłem trochę google, ale wszędzie wyglądam negatywnie. Obecnie mam sytuację podobną do następującej:
class GenericClass<T>
{
public event EventHandler<EventData> MyEvent;
public class EventData : EventArgs { /* snip */ }
// ... snip
}
Teraz naukowiec od rakiet nie musi zorientować się, że może to bardzo szybko doprowadzić do wielu pisania (przepraszam za okropną grę słów) podczas próby zaimplementowania modułu obsługi tego zdarzenia. Ostatecznie byłoby to mniej więcej tak:
GenericClass<int> gcInt = new GenericClass<int>;
gcInt.MyEvent += new EventHandler<GenericClass<int>.EventData>(gcInt_MyEvent);
// ...
private void gcInt_MyEvent(object sender, GenericClass<int>.EventData e)
{
throw new NotImplementedException();
}
Tyle że w moim przypadku użyłem już złożonego typu, a nie tylko int. Byłoby miło, gdyby można to trochę uprościć ...
Edycja: tj. być może należy wpisać typ EventHandler zamiast konieczności jego redefiniowania, aby uzyskać podobne zachowanie.
using MyClassDictionary = System.Collections.Generic.Dictionary<System.String, MyNamespace.MyClass>;
Czy jest poprawna? W przeciwnym razie wydaje się, że nie bierze pod uwagęusing
powyższych definicji.typedef uint8 myuuid[16];
za pomocą dyrektywy „using”.using myuuid = Byte[16];
nie kompiluje się.using
może być używany tylko do tworzenia aliasów typów .typedef
wydaje się być znacznie bardziej elastyczny, ponieważ może utworzyć alias dla całej deklaracji (w tym rozmiarów tablicy). Czy w tym przypadku jest jakaś alternatywa?Jon naprawdę dał dobre rozwiązanie, nie wiedziałem, że możesz to zrobić!
Czasem uciekałem się po dziedziczeniu od klasy i tworzeniu jej konstruktorów. Na przykład
Nie jest to najlepsze rozwiązanie (chyba że twój zespół zostanie wykorzystany przez inne osoby), ale działa.
źródło
public class FooList : LikeType<IReadOnlyList<Foo>> { ... }
, a następnie używać go w dowolnym miejscu można się spodziewaćIReadOnlyList<Foo>
. Moja odpowiedź poniżej pokazuje więcej szczegółów.Foo
jeśli zostanie przekazany np. Do metody szablonu, która akceptujeList<T>
. Przy odpowiednim typowaniu byłoby to możliwe.Jeśli wiesz, co robisz, możesz zdefiniować klasę z niejawnymi operatorami w celu konwersji między klasą aliasu i klasą rzeczywistą.
W rzeczywistości nie popieram tego i nigdy nie użyłem czegoś takiego, ale prawdopodobnie mogłoby to zadziałać w pewnych szczególnych okolicznościach.
źródło
C # obsługuje pewne odziedziczone kowariancje dla delegatów zdarzeń, więc metoda taka jak ta:
Może być wykorzystany do zasubskrybowania Twojego wydarzenia, nie jest wymagana jawna obsada
Możesz nawet użyć składni lambda, a inteligencja zostanie zrobiona za Ciebie:
źródło
Myślę, że nie ma maszynopisu. Możesz zdefiniować tylko określony typ delegata zamiast ogólnego w GenericClass, tj
To by było krótsze. Ale co z następującą sugestią:
Użyj programu Visual Studio. W ten sposób podczas pisania
zapewnia już pełny podpis procedury obsługi zdarzeń od Intellisense. Naciśnij TAB i już tam jest. Zaakceptuj wygenerowaną nazwę procedury obsługi lub zmień ją, a następnie ponownie naciśnij klawisz TAB, aby automatycznie wygenerować kod pośrednika procedury obsługi.
źródło
Zarówno C ++, jak i C # nie mają łatwych sposobów na stworzenie nowego typu, który jest semantycznie identyczny z istniejącym typem. Uważam, że takie „typedefs” są absolutnie niezbędne dla programowania bezpiecznego dla typu i szkoda, że c # nie ma ich wbudowanych. Różnica między
void f(string connectionID, string username)
celuvoid f(ConID connectionID, UserName username)
jest oczywiste ...(Możesz osiągnąć coś podobnego w C ++ dzięki wzmocnieniu w BOOST_STRONG_TYPEDEF)
Używanie dziedziczenia może być kuszące, ale ma to pewne poważne ograniczenia:
Jedynym sposobem na osiągnięcie podobnej rzeczy w języku C # jest skomponowanie naszego typu w nowej klasie:
Chociaż to zadziała, jest to bardzo szczegółowe dla samego typedef. Ponadto mamy problem z serializacją (tj. Json), ponieważ chcemy serializować klasę za pomocą jej właściwości Composed.
Poniżej znajduje się klasa pomocnicza, która wykorzystuje „Ciekawie powtarzający się wzorzec szablonu”, aby uprościć to:
Dzięki Composer powyższa klasa staje się po prostu:
A ponadto
SomeTypeTypeDef
serializuje do Jsona w ten sam sposób, coSomeType
robi.Mam nadzieję że to pomoże !
źródło
Możesz użyć biblioteki Open Source i pakietu NuGet o nazwie LikeType, który stworzyłem, co zapewni ci
GenericClass<int>
zachowanie, którego szukasz.Kod wyglądałby następująco:
źródło
LikeType
biblioteki.LikeType
głównym celem jest pomoc w Primitive Obsession , i dlatego nie chce, abyś mógł ominąć zawinięty typ, tak jak to był typ owijania. Tak jak w przypadku, jeśli to zrobię,Age : LikeType<int>
to jeśli moja funkcja potrzebuje anAge
, chcę upewnić się, że moje osoby dzwoniące przekazują anAge
, a nie anint
.Oto jego kod, baw się !, wybrałem to z dotNetReference wpisz polecenie „using” wewnątrz linii przestrzeni nazw 106 http://referencesource.microsoft.com/#mscorlib/microsoft/win32/win32native.cs
źródło
W przypadku niezapieczętowanych klas po prostu dziedzicz po nich:
Ale dla klas zapieczętowanych można symulować zachowanie typedef za pomocą takiej klasy bazowej:
źródło
Najlepszą alternatywą dla
typedef
tego, co znalazłem w C #, jestusing
. Na przykład mogę kontrolować precyzję ruchu zmiennego za pomocą flag kompilatora za pomocą tego kodu:Niestety wymaga to umieszczenia tego na górze każdego pliku, którego używasz
real_t
. Obecnie nie ma możliwości zadeklarowania globalnego typu przestrzeni nazw w języku C #.źródło