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.} }
仅适合喜欢玩数字游戏的开发者(谁没有!)。
您将在下面找到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); }
它可能是为了处理转换构造函数允许操作的情况,但显然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"); }