IsignableFrom или AS? - PullRequest
       17

IsignableFrom или AS?

5 голосов
/ 03 августа 2010

У меня есть следующий код:

private T CreateInstance<T>(object obj) // where T : ISomeInterface, class
{
    ...

    if (!typeof(T).IsAssignableFrom(obj.GetType())) { throw ..; }

    return (T)obj;
}

Можно ли заменить на это:

T result = obj as T;

if (result == null) { throw ..; }

return result;

Если нет - почему?

Ответы [ 11 ]

6 голосов
/ 03 августа 2010

А как насчет if (!(bar is T)) { throw ..; }

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

4 голосов
/ 03 августа 2010

Другой вариант:

private T CreateInstance<T>(object obj) where T : ISomeInterface // as OP mentioned above
{
    ...

    T result = obj as T;
    if (result == null)
        { throw ..; }
    else 
       return result;
}
3 голосов
/ 03 августа 2010

Да, вы можете использовать свой код оператора as вместо исходного кода, если T является ссылочным типом или может иметь значение NULL.

as - рекомендуемый способ приведения в C # (см. Пункт 3 «Эффективного C #» Билла Вагнера)

Из system.type.isassignablefrom :

[возвращает] true, если c и текущий Тип представляют один и тот же тип, или если текущий Тип находится в иерархии наследования c, или если текущий Тип является интерфейсом, который реализует c, или если c является универсальным типом параметр и текущий тип представляет собой одно из ограничений c. false, если ни одно из этих условий не выполняется, или если c равно нулю.

От 7.10.11 C # spec:

В операции формы E как T, E должно быть выражением, а T должно быть ссылочным типом, параметром типа, известным как ссылочный тип, или обнуляемым типом

Итак, вы можете видеть, что они делают сопоставимые проверки.

2 голосов
/ 03 августа 2010

Может быть, это (меньше скобок, лучшая читаемость)

if (obj is T)
{
    return (T)obj;
}
else
   throw new ...

EDITED по уменьшенному количеству скобок, я изначально имел в виду инвертированную проверку: т.е.

if (!(obj is T))

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

if (obj is T)
{
    return (T)obj;
}

throw new ...

или

if (obj is T)
{
    return (T)obj;
}
else
{
   throw new ...
}
1 голос
/ 24 мая 2012

IsAssignableFrom используется этой сценой:

foreach (PropertyInfo property in GetType().GetProperties())
{
    if (typeof(SubPresenter).IsAssignableFrom(property.PropertyType))
    {//Do Sth.}
}
1 голос
/ 03 августа 2010

Возможно, вы ищете ключевое слово is с синтаксисом expression is type

Документация описывает это как выполнение необходимых проверок:

Выражение is равно true, если оба из следующих условий встретил:

• выражение не является нулевым.

• выражение может быть приведен к типу. То есть бросок выражение формы (тип) (выражение) будет завершено без исключения.

Редактировать Однако, если вместо того, чтобы просто определить, можете ли вы что-то разыграть перед попыткой, ключевое слово as, вероятно, будет вашим лучшим решением, как вы описали в своем посте.

Следующий код будет выполнять ту же функцию, хотя ...

try
{
    T result = (T)obj;
    return result;
}
catch (InvalidCastException ex)
{
     // throw your own exception or deal with it in some other way.
}

Какой метод вы предпочитаете, зависит от вас ...

1 голос
/ 03 августа 2010

Ограничение класса where T : class позволяет использовать оператор as T.

private T CreateInstance<T>(object obj) where T : class
{
    if (!(obj is T)) { throw new ArgumentException("..."); }
    return obj as T;
}

или

private T CreateInstance<T>(object obj)
{
    if (!(obj is T)) { throw new ArgumentException("..."); }
    return (T)obj;
}
1 голос
/ 03 августа 2010

См. этот пост

Второй безопасен ... потому что на первом, если obj равен нулю, вы получите исключение (obj.GetType () -> NullReferenceException),

Когда вы ставите «есть», а затем «как» является причиной проблемы с производительностью ..

0 голосов
/ 03 июля 2014

Только для разработчиков, которые любят играть в игру чисел (а кто нет!).

Ниже вы найдете тест сравнения производительности для IsAssignableFrom против As . Конечно, это будет учитываться, только если у вас есть экземпляр.

Результат теста (миллион попыток):

IsAssignableFrom: 146 мс прошло

AsOperator: 7 мс прошло

[TestMethod]
public void IsAssignableFromVsAsPerformanceTest()
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    int attempts = 1000000;
    string value = "This is a test";

    for (int attempt = 0; attempt < attempts; attempt++) {
        bool isConvertible = typeof(IConvertible).IsAssignableFrom(value.GetType());
    }

    stopwatch.Stop();
    Console.WriteLine("IsAssignableFrom: {0} ms elapsed", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attempt = 0; attempt < attempts; attempt++) {
        bool isConvertible = value as string != null;
    }

    stopwatch.Stop();
    Console.WriteLine("AsOperator: {0} ms elapsed", stopwatch.ElapsedMilliseconds);
}
0 голосов
/ 03 августа 2010

Возможно, он предназначен для обработки случаев, когда конструктор преобразования разрешает операцию, но, очевидно, IsAssignableFrom также не обрабатывает это. Не вижу ничего, что может справиться с этим. Поэтому я не вижу, как проверять такие случаи:

class Program
{
  static void Main(string[] args)
  {
     B bValue = new B(123);
     Console.WriteLine(typeof(A).IsAssignableFrom(bValue.GetType()));
     //Console.WriteLine(bValue is A);
     //Console.WriteLine(bValue as A == null);
     A aValue = bValue;
     Console.WriteLine(aValue.ToString());
  }
}

class A
{
  string value;
  public A(string value)
  {
     this.value = value;
  }
  public override string ToString()
  {
     return value;
  }
}

class B
{
  int value;

  public B(int value)
  {
     this.value = value;
  }

  public static implicit operator A(B value)
  {
     return new A(value.value.ToString());
  }
}

В конце концов, я не вижу никакой причины, по которой вы не захотите использовать свою версию кода, если только вы не хотите код, выдавший исключение, когда значение obj равно нулю. Это единственное отличие, которое я вижу. obj.GetType () сгенерирует исключение с нулевой ссылкой, когда obj имеет значение NULL, а не сгенерирует указанное исключение.

Редактировать: Теперь я вижу, что ваша версия кода не будет компилироваться, если T может быть типом значения, но другое предлагаемое решение, такое как "if (obj is T) return (T) obj;" скомпилирует. Поэтому я понимаю, почему предложенная вами альтернатива не будет работать, но я не понимаю, почему вы не можете использовать «is».

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