IsAssignableFrom还是AS?

我有下一个代码:

private T CreateInstance(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; 

如果不是 – 为什么?

另一个变种:

 private T CreateInstance(object obj) where T : ISomeInterface // as OP mentioned above { ... T result = obj as T; if (result == null) { throw ..; } else return result; } 

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

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

 return (T)obj; 

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

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

推荐的C#铸造方式(参见Bill Wagner的有效C#第3项)

来自system.type.isassignablefrom :

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

从C#规范的7.10.11开始:

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

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

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

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

通过减少数量的括号来编辑我最初的意思是倒置检查:即

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

看这篇文章

第二个是安全的……因为在第一个如果obj为null,你将得到exception(obj.GetType() – > NullReferenceException)。

当你放置“是”然后“as”导致性能问题..

类约束where T : class允许您使用as T语句。

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

要么

 private T CreateInstance(object obj) { if (!(obj is T)) { throw new ArgumentException("..."); } return (T)obj; } 

你可能正在寻找is关键字,语法expression is type

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

如果满足以下两个条件,则表达式的计算结果为true:

•表达式不为空。

•表达式可以转换为类型。 也就是说,forms(类型)(表达式)的强制转换表达式将在不抛出exception的情况下完成。

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

以下代码将执行相同的function,但……

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

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

IsAssignableFrom由此场景使用:

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

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

您将在下面找到IsAssignableFromAs的性能对比测试。 当然,只有你有一个实例,这才算数。

测试结果(一百万次尝试):

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

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

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

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

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