Generics w C#, używając typu zmiennej jako parametru [duplikat]

To pytanie ma już odpowiedź tutaj:

I have a generic method

bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

Jak używać metody w następujący sposób:

Type t = entity.GetType();
DoesEntityExist<t>(entityGuid, transaction);

Ciągle otrzymuję błąd kompilacji:

Nazwa typu lub przestrzeni nazw " t " może nie można znaleźć (są brakuje Ci dyrektywa czy odniesienie do Zgromadzenia?)

DoesEntityExist<MyType>(entityGuid, transaction);

Działa doskonale, ale nie chcę używać dyrektywy if do wywoływania metody z osobną nazwą typu za każdym razem.

Author: Germstorm, 2010-01-21

4 answers

Chodzi o to, aby zapewnić czas kompilacji bezpieczeństwo typu - co oznacza, że typy muszą być znane w czasie kompilacji.

Ty możesz wywoływać metody generyczne z typami znanymi tylko w czasie wykonywania, ale musisz użyć reflection:

// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
                             .MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });

Ick.

Czy możesz zamiast tego uczynić metodę wywołującą i przekazać parametr type jako argument type, przesuwając decyzję o jeden poziom wyżej w górę stosu?

If you could give us more informacje o tym, co robisz, to by pomogło. Czasami może być konieczne użycie odbicia jak powyżej, ale jeśli wybierzesz odpowiedni punkt, aby to zrobić, możesz upewnić się, że musisz to zrobić tylko raz i pozwolić wszystkim poniżej tego punktu używać parametru type w normalny sposób.

 147
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-11 06:49:53

Jednym ze sposobów obejścia tego jest użycie ukrytego odlewania:

bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

Nazywając to tak:

DoesEntityExist(entity, entityGuid, transaction);

Idąc o krok dalej, możesz przekształcić ją w metodę rozszerzenia (będzie ona musiała być zadeklarowana w klasie statycznej):

static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;

Wywołanie Tak:

entity.DoesEntityExist(entityGuid, transaction);
 31
Author: Joe Lloyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-21 08:45:09

Nie jestem pewien, czy dobrze rozumiem twoje pytanie, ale możesz napisać swój kod w ten sposób:

bool DoesEntityExist<T>(T instance, ....)

Możesz wywołać metodę w następujący sposób:

DoesEntityExist(myTypeInstance, ...)

W ten sposób nie musisz jawnie zapisywać typu, framework automatycznie przejmie Typ od instancji.

 7
Author: kosto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-21 08:44:15

Nie możesz tego użyć w sposób, w jaki opisujesz. Chodzi o to, że chociaż możesz nie znać ich w "czasie kodowania", kompilator musi być w stanie je rozwiązać w czasie kompilacji. Dlaczego? Ponieważ pod maską kompilator odejdzie i utworzy nowy typ (czasami nazywany zamkniętym typem generycznym) dla każdego innego użycia "otwartego" typu generycznego.

Innymi słowy, po kompilacji,

DoesEntityExist<int>

Jest innym typem

DoesEntityExist<string>

Oto jak kompilator jest w stanie zapewnić bezpieczeństwo typu compile-time.

Dla scenariusza, który opisujesz, powinieneś przekazać Typ jako argument, który można zbadać w czasie wykonywania.

Inną opcją, jak wspomniano w innych odpowiedziach, jest użycie refleksji do tworzenia typu zamkniętego z typu otwartego, chociaż prawdopodobnie jest to zalecane w cokolwiek innego niż ekstremalne scenariusze niszowe, powiedziałbym.

 4
Author: Rob Levine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-21 08:42:34