C# 运算符as和泛型类
我正在为CLR脚本编写编译器,并希望执行方法使泛型可接受:C# 运算符as和泛型类,c#,.net,generics,operators,on-the-fly,C#,.net,Generics,Operators,On The Fly,我正在为CLR脚本编写编译器,并希望执行方法使泛型可接受: object Execute() { return type.InvokeMember(..); } T Execute<T>() { 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 typ
object Execute()
{
return type.InvokeMember(..);
}
T Execute<T>()
{
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
}
对象执行()
{
返回类型。InvokeMember(..);
}
T Execute()
{
将Execute()返回为T;/*不起作用:
类型参数“T”不能与“as”运算符一起使用,因为
它既没有类类型约束,也没有“类”约束*/
//此外,typeof(T)和T.GetType()等都不可能
return(T)Execute();//确定
}
但我认为操作符as
将非常有用:如果结果类型不是t
方法将返回null
,而不是异常!可以这样做吗?您需要添加
where T : class
方法声明,例如
T Execute<T>() where T : class
{
或者,如果他们想放弃失败:
MyClass c = (MyClass)whatever.Execute();
通用包装器方法如下所示:
MyClass c = whatever.Execute<MyClass>();
MyClass c=whatever.Execute();
所有三个版本都必须以不同的顺序指定完全相同的三个实体,因此没有一个更简单或更方便,但通用版本隐藏了正在发生的事情,而“原始”版本都清楚地说明了是抛出还是null
(如果从实际代码中简化示例,则这可能与您无关)。您不能将
as
运算符与泛型类型一起使用,而不受任何限制。由于as
运算符使用null表示它不是该类型,因此不能在值类型上使用它。如果您想使用obj作为T
,T
将作为参考类型
T Execute<T>() where T : class
{
return Execute() as T;
}
T Execute(),其中T:class
{
将Execute()返回为T;
}
看起来您只是添加了一个包装器方法来强制转换用户想要的类型,因此只会增加执行的开销。对于用户来说,编写
int result = Execute<int>();
您可以使用out修饰符将结果写入调用者作用域中的变量,并返回一个布尔标志以指示是否成功:
bool Execute<T>(out T result) where T : class
{
result = Execute() as T;
return result != null;
}
bool执行(out T result),其中T:class
{
结果=执行()为T;
返回结果!=null;
}
Execute()是否有可能返回值类型?如果是这样,那么您需要Earwicker的类类型方法,以及另一个值类型通用方法。可能是这样的:
Nullable<T> ExecuteForValueType<T> where T : struct
然后,您必须获取rawResult的类型,并查看是否可以将其分配给T:
Nullable<T> finalReturnValue = null;
Type theType = rawResult.GetType();
Type tType = typeof(T);
if(tType.IsAssignableFrom(theType))
{
finalReturnValue = tType;
}
return finalReturnValue;
Nullable finalReturnValue=null;
键入Type=rawResult.GetType();
类型tType=类型(T);
if(tType.IsAssignableFrom(类型))
{
finalReturnValue=tType;
}
返回finalReturnValue;
最后,让原始的Execute消息找出T的类型(类或结构类型),并调用相应的实现
注意:这是来自粗略的记忆。我大约一年前就这样做了,可能记不清每一个细节。尽管如此,我还是希望为您指出大致的方向会有所帮助。这段代码是对as-关键字的异常安全替代:
return Execute() is T value ? value : default(T)
它使用了C#7引入的模式匹配功能。
如果您不想将泛型参数限制为引用类型,请使用它非常感谢您的回答。我会用它,勾选和标记作为答案。我还有下一个代码用法:MyClass c=compiler.Execute();我认为它比MyClass c=compiler.Execute()作为MyClass更好;(我想,内部检查比外部检查更好)但是外部仍然需要检查-检查null:)通过让用户写'asmyclass',您可以更清楚地看到需要检查null。Hm。。看来你是对的!我建议使用“正常”Execute(),但对于最终用户来说,使用这种“异常”Execute()可能会有所帮助,另外还有一些“通用实验”:
object rawResult = Execute();
Nullable<T> finalReturnValue = null;
Type theType = rawResult.GetType();
Type tType = typeof(T);
if(tType.IsAssignableFrom(theType))
{
finalReturnValue = tType;
}
return finalReturnValue;
return Execute() is T value ? value : default(T)