我有下一个代码:
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;
如果不是 - 为什么?
答案 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");
}