C# 运算符as和泛型类

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

我正在为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 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)