IsAssignableFrom还是AS?

时间:2010-08-03 12:57:05

标签: c# generics inheritance interface

我有下一个代码:

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 个答案:

答案 0 :(得分:6)

if (!(bar is T)) { throw ..; }

怎么样?

或者,如果您不需要自己的异常消息,最简单的答案就是:

return (T)obj;

如果它不能转换为InvalidCastException的原因将被抛出并且返回被忽略。除非您添加更多逻辑或自定义错误消息,否则无需进行检查并抛出您自己的异常。

答案 1 :(得分:4)

另一种变体:

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

答案 2 :(得分:3)

是的,您可以在那里使用as运算符代码而不是原始代码,只要T是引用类型或可为空即可。

as是C#中推荐的推荐方法(见Bill Wagner的有效C#第3项)

来自system.type.isassignablefrom

  

[returns]如果c和当前Type表示相同类型,或者当前Type在c的继承层次结构中,或者当前Type是c实现的接口,或者c是泛型类型,则返回true参数和当前Type表示c的约束之一。如果这些条件均不为真,或者c为空,则返回false。

从C#规范的7.10.11开始:

  

在E形式的操作中,E必须是表达式,T必须是引用类型,已知为引用类型的类型参数或可空类型

所以你可以看到他们做了类似的检查。

答案 3 :(得分:2)

也许这个(括号更少,可读性更好)

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

<强> EDITED 通过减少支架数量我原来的意思是倒置检查:即

if (obj is T)

而不是

if (!(obj is T))

所以最终版本可以是

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

throw new ...

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

答案 4 :(得分:1)

请参阅this post

第二个是安全的...因为在第一个如果obj为null,你将获得异常(obj.GetType() - &gt; NullReferenceException)。

当你放置“是”然后“as”是因为performance issues..

答案 5 :(得分:1)

类约束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;
}

答案 6 :(得分:1)

您可能正在寻找is关键字,其语法为expression is type

Documentation将其描述为执行所需的检查:

  

如果是,表达式的计算结果为true   以下两个条件都是   见过:

     

•表达式不为空。

     

•表达   可以转换为类型。就是演员   形式的表达   (类型)(表达式)将完成   没有抛出异常。

修改 但是,如果您在尝试之前无法确定是否可以投射某些内容,那么as关键字可能是您在帖子中描述的最佳解决方案。

以下代码会执行相同的功能......

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

您更喜欢哪种方法取决于您......

答案 7 :(得分:1)

此场景使用IsAssignableFrom:

foreach (PropertyInfo property in GetType().GetProperties())
{
    if (typeof(SubPresenter).IsAssignableFrom(property.PropertyType))
    {//Do Sth.}
}

答案 8 :(得分:0)

仅适合喜欢玩数字游戏的开发者(谁不会!)。

在您的下方,我们会找到 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);
}

答案 9 :(得分:-2)

它可能是为了处理转换构造函数允许操作的情况,但显然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为null时抛出异常。这是我能看到的唯一区别。当obj为null而不是抛出指定的异常时,obj.GetType()将抛出一个空引用异常。

编辑:我现在看到,如果T可以是值类型,那么您的代码版本将无法编译,但另一个建议的解决方案如“if(obj is T)return(T)obj; “将编译。所以我明白为什么你建议的替代方案不起作用,但我不明白为什么你不能使用“是”。

答案 10 :(得分:-3)

甚至更好,因为它更容易阅读真正的条件。

 if(obj is T){
    //Create instance. 
 }
 else{
    throw new InvalidArgumentException("Try Again");
 }