Подтвердить что ты не робот

Оператор как и общие классы

Я пишу . Компилятор NET On-the-Fly для сценариев CLR и хочет, чтобы метод выполнения делал общепринятым:

object Execute()
{
  return type.InvokeMember(..);
}

T Execute<T>()
{
  return Execute() as T; /* doesn't work:
  The type parameter 'T' cannot be used with the 'as' operator because
  it does not have a class type constraint nor a 'class' constraint */

  // also neither typeof(T) not T.GetType(), so on are possible

  return (T) Execute(); // ok
}

Но я думаю, что оператор as будет очень полезен: если тип результата не является T, метод вернет null вместо исключения! Можно ли это сделать?

4b9b3361

Ответ 1

Вам нужно добавить

where T : class

к объявлению вашего метода, например

T Execute<T>()  where T : class
{

Кстати, как предположение, эта общая оболочка на самом деле не добавляет большого значения. Вызывающий может написать:

MyClass c = whatever.Execute() as MyClass;

Или если они хотят сбросить сбой:

MyClass c = (MyClass)whatever.Execute();

Общий метод обертки выглядит следующим образом:

MyClass c = whatever.Execute<MyClass>();

Все три версии должны указывать точно те же три сущности, только в разных порядках, поэтому ни один из них не является более простым или более удобным, но все же общая версия скрывает то, что происходит, тогда как "исходные" версии дают понять будет ли бросок или null.

(Это может быть неуместно для вас, если ваш пример упрощен от вашего фактического кода).

Ответ 2

Вы не можете использовать оператор as с общим типом без ограничений. Поскольку оператор as использует null, чтобы представить, что он не относится к типу, вы не можете использовать его для типов значений. Если вы хотите использовать obj as T, T будет иметь ссылочный тип.

T Execute<T>() where T : class
{
  return Execute() as T;
}

Ответ 3

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

int result = Execute<int>();

не сильно отличается от

int result = (int)Execute();

Вы можете использовать модификатор out для записи результата в переменную в области вызывающего объекта и вернуть флаг boolean, чтобы определить, удалось ли это:

bool Execute<T>(out T result) where T : class
{
    result = Execute() as T;
    return result != null;
}

Ответ 4

Есть ли вероятность, что функция Execute() может вернуть тип значения? Если это так, то вам нужен метод Earwicker для типов классов и другой общий метод для типов значений. Может выглядеть так:

Nullable<T> ExecuteForValueType<T> where T : struct

Логика внутри этого метода скажет

object rawResult = Execute();

Затем вам нужно будет получить тип rawResult и посмотреть, может ли он быть назначен для T:

Nullable<T> finalReturnValue = null;

Type theType = rawResult.GetType();
Type tType = typeof(T);

if(tType.IsAssignableFrom(theType))
{
    finalReturnValue = tType;     
}

return finalReturnValue;

Наконец, сделайте свое исходное сообщение об ошибке выполнения, которое имеет T (класс или тип структуры), и вызовите соответствующую реализацию.

Примечание. Это из грубой памяти. Я сделал это примерно год назад и, вероятно, не помню каждую деталь. Тем не менее, я надеюсь, что указывать вам в общем направлении помогает.