运算符as和generics类

我正在为CLR脚本编写.NET On-the-Fly编译器,并希望执行方法使得generics可接受:

object Execute() { return type.InvokeMember(..); } T Execute() { return Execute() as T; /* doesn't work: The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint */ // also neither typeof(T) not T.GetType(), so on are possible return (T) Execute(); // ok } 

但我觉得运算符非常有用:如果结果类型不是T方法将返回null ,而不是exception! 有可能吗?

你需要添加

 where T : class 

你的方法声明,例如

 T Execute() where T : class { 

顺便说一下,作为一个建议,通用包装器并没有真正增加太多价值。 来电者可以写:

 MyClass c = whatever.Execute() as MyClass; 

或者如果他们想要失败:

 MyClass c = (MyClass)whatever.Execute(); 

通用包装器方法如下所示:

 MyClass c = whatever.Execute(); 

所有三个版本必须指定完全相同的三个实体,只是在不同的顺序,所以没有更简单或更方便,但通用版本隐藏了正在发生的事情,而“原始”版本每个都清楚地说明是否会是一个抛出或null

(如果您的示例是从实际代码中简化的话,这可能与您无关)。

您不能将as运算符与没有限制的generics类型一起使用。 由于as运算符使用null来表示它不是类型,因此不能在值类型上使用它。 如果要将obj as T ,则T 必须是引用类型。

 T Execute() where T : class { return Execute() as T; } 

这段小代码是as -keyword的exception安全替代:

 return Execute() is T value ? value : default(T) 

它使用C#7引入的模式匹配function。如果您不想将generics参数限制为引用类型,请使用它

看起来您只是添加了一个包装器方法,用于转换为用户想要的类型,因此只会增加执行的开销。 对于用户来说,写作

 int result = Execute(); 

并没有太大的不同

 int result = (int)Execute(); 

您可以使用out修饰符将结果写入调用者范围内的变量,并返回一个布尔标志来判断它是否成功:

 bool Execute(out T result) where T : class { result = Execute() as T; return result != null; } 

Execute()是否有可能返回值类型? 如果是这样,那么你需要Earwicker的类类型方法,以及值类型的另一种通用方法。 可能看起来像这样:

 Nullable ExecuteForValueType where T : struct 

该方法内部的逻辑会说

 object rawResult = Execute(); 

然后,你必须得到rawResult的类型,看看它是否可以分配给T:

 Nullable finalReturnValue = null; Type theType = rawResult.GetType(); Type tType = typeof(T); if(tType.IsAssignableFrom(theType)) { finalReturnValue = tType; } return finalReturnValue; 

最后,让您的原始Execute消息确定哪个T具有(类或结构类型),并调用适当的实现。

注意:这是来自粗略的记忆。 大约一年前我这样做了,可能不记得每一个细节。 不过,我希望指出你在总体方向上有所帮助。