Brzmi to co trzeba jest typ interfejsu, a nie delegata. Metody interfejsu akceptują otwarte typy ogólne (to jest to, czego szukasz), mimo że delegaci nie mogą. Na przykład, można określić coś takiego:
interface ActOnConstrainedThing<CT1,CT2>
{
void Act<MainType>(MainType param) where MainType: CT1,CT2;
}
Nawet jeśli realizatorów CT1
i CT2
nie mają wspólny typ bazowy, który również implementuje CT1
i CT2
, implementacja Act
może używać przekazany w parametr jako CT1
lub CT2
bez typowania, a nawet może przekazać go do procedur, które oczekują ogólnego parametru z ograniczeniami CT1
i CT2
. Taka rzecz nie byłaby możliwa z delegatami.
Należy zauważyć, że używanie interfejsów zamiast delegatów oznacza, że nie można używać normalnego mechanizmu i składni "zdarzenia". Zamiast tego obiekt, który byłby wydawcy zdarzenia, musi utrzymywać listę instancji obiektów, które implementują pożądany interfejs (np. List<ActOnConstrainedThing<IThis,IThat>>
) i wyliczyć wystąpienia na tej liście (być może używając foreeach
). Na przykład:
List<IActOnConstrainedThing<IThis,IThat>> _ActOnThingSubscribers;
void ActOnThings<T>(T param) where T:IThis,IThat
{
foreach(var thing in _ActOnThingSubscribers)
{
thing.Act<T>(param);
}
}
Edycja/Uzupełnienie
miejsce gdzie zatrudniony ten wzór miał także kilka innych rzeczy, które nie wydają się zbyt istotne pytanie, które przez moją interpretacją pytał, jak jeden może mieć delegata (lub odpowiednik) z parametrem typu otwartego, dzięki czemu obiekt wywołujący odpowiednik delegata może dostarczyć parametr typu, bez potrzeby dostarczania obiektu podmiotu delegującego, który musi go znać wcześniej. W większości przypadków, gdzie jest to przydatne obejmować ogólne ograniczenia, ale od tego najwyraźniej wprowadzającej w błąd, oto przykład, że nie:
interface IShuffleFiveThings
{
void Shuffle<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5);
}
List<IShuffleFiveThings _ShuffleSubscribers;
void ApplyShuffles<T>(ref T p1, ref T p2, ref T p3, ref T p4, ref T p5)
{
foreach(var shuffler in _ShuffleSubscribers)
{
thing.Shuffle(ref p1, ref p2, ref p3, ref p4, ref p5);
}
}
Sposób IShuffleFiveThings.Shuffle<T>
trwa pięć parametrów przez ref
i robi coś z nich (najprawdopodobniej permutacji w jakiś sposób, być może permutując je losowo, lub może permutując niektóre losowo, pozostawiając innych tam, gdzie są.Jeśli ma się listę IShuffleFiveThings
, rzeczy na tej liście mogą być wykorzystywane efektywnie, bez boksowania lub Odbicia, do manipulowania wszelkiego rodzaju rzeczami (w tym zarówno typami klas, jak i typami wartości). Natomiast, jeśli jeden z nich korzystać delegatów:
delegate void ActOn5RefParameters(ref p1, ref p2, ref p3, ref p4, ref p5);
potem bo jakaś konkretna instancja delegat może działać tylko na jednym rodzaju parametrów dostarczanego na jego powstania (o ile nie jest to otwarty delegata, który nazywa się tylko za pośrednictwem refleksji), jeden musiałby utworzyć osobną listę delegatów dla każdego typu obiektu, który chciałby przetasować (tak, wiem, że normalnie obsłużyłby permutacje za pomocą tablicy indeksów całkowitych, wybrałem permutację jako operację, ponieważ dotyczy ona wszystkich obiektów typy, nie dlatego, że ta konkretna metoda permutacji rzeczy jest przydatna).
Należy pamiętać, że ponieważ typ T
w IShuffleFiveThings
nie ma żadnych ograniczeń, implementacje nie będą w stanie z nim wiele zrobić, z wyjątkiem operacji typowania (która może wprowadzić boksowanie). Dodanie ograniczeń do takich parametrów czyni je znacznie bardziej użytecznymi. Chociaż możliwe byłoby sztywne kodowanie takich ograniczeń w interfejsie, ograniczyłoby to przydatność interfejsu dla aplikacji wymagających tych konkretnych ograniczeń. Wykonywanie samych ograniczeń przez unikanie tego ograniczenia.
Kompilator nie zaakceptuje właściwości o nieznanym typie ogólnym, która nie może być znana do czasu wykonania. – BoltClock
Czego można się spodziewać? – SLaks
Chcę przekazać ogólny parametr w zdarzeniu. To wszystko. Na pewno, gdybym wiedział, jaki typ T byłby w czasie kompilacji, nie musiałbym w ogóle używać generycznych? – Xenoprimate