Generics в С#, используя тип переменной в качестве параметра

У меня есть общий метод

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

Как использовать метод следующим образом:

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

Я продолжаю получать обманную ошибку компиляции:

Тип или имя пространства имен 't' может не найти (вы не используете директива или ссылка на сборку?)

DoesEntityExist<MyType>(entityGuid, transaction);

работает отлично, но я не хочу использовать директиву if, чтобы каждый раз вызывать метод с отдельным именем типа.

Ответ 1

Точка о дженериках заключается в предоставлении безопасности типа компиляции - что означает, что типы должны быть известны во время компиляции.

Вы можете вызывать общие методы с типами, известными только во время выполнения, но вы должны использовать отражение:

// 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 });

Ик.

Можете ли вы сделать свой метод вызова generic вместо этого и передать свой параметр типа в качестве аргумента типа, нажав решение на один уровень выше стека?

Если бы вы могли дать нам больше информации о том, что вы делаете, это поможет. Иногда вам может понадобиться использовать отражение, как указано выше, но если вы выберете правильную точку, чтобы сделать это, вы можете убедиться, что вам нужно сделать это только один раз, и пусть все ниже этой точки будет использовать параметр типа обычным способом.

Ответ 2

Один из способов обойти это - использовать неявное литье:

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

вызывает его так:

DoesEntityExist(entity, entityGuid, transaction);

Идя дальше, вы можете превратить его в метод расширения (его нужно будет объявить в статическом классе):

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

вызывающий так:

entity.DoesEntityExist(entityGuid, transaction);

Ответ 3

Я не уверен, правильно ли я понял ваш вопрос, но вы можете написать свой код следующим образом:

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

Вы можете вызвать метод следующим образом:

DoesEntityExist(myTypeInstance, ...)

Таким образом, вам не нужно явно писать тип, структура автоматически обгонит этот тип из экземпляра.

Ответ 4

Вы не можете использовать его так, как вы описываете. Точка о родовых типах заключается в том, что, хотя вы можете не знать их в "время кодирования", компилятор должен иметь возможность разрешать их во время компиляции. Зачем? Потому что под капотом компилятор уйдет и создаст новый тип (иногда называемый замкнутым родовым типом) для каждого различного использования "открытого" родового типа.

Другими словами, после компиляции

DoesEntityExist<int>

- это другой тип для

DoesEntityExist<string>

Таким образом, компилятор может обеспечить безопасность типа компиляции.

В описываемом сценарии вы должны передать этот тип в качестве аргумента, который можно проверить во время выполнения.

Другим вариантом, как упоминалось в других ответах, является использование рефлексии для создания закрытого типа из открытого типа, хотя это, вероятно, рекомендуется в любых сценариях, отличных от экстремальных ниш, которые я бы сказал.