C# 运算符 as 和泛型类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/693463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 13:44:36  来源:igfitidea点击:

Operator as and generic classes

c#.netgenericsoperatorson-the-fly

提问by abatishchev

I'm writing .NET On-the-Flycompiler for CLR scripting and want execution method make generic acceptable:

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

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
}

But I think operator aswill be very useful: if result type isn't Tmethod will return null, instead of an exception! Is it possible to do?

但我认为运算符as会非常有用:如果结果类型不是T方法将返回null,而不是异常!有可能吗?

采纳答案by Daniel Earwicker

You need to add

你需要添加

where T : class

to your method declaration, e.g.

到您的方法声明,例如

T Execute<T>()  where T : class
{

By the way, as a suggestion, that generic wrapper doesn't really add much value. The caller can write:

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

MyClass c = whatever.Execute() as MyClass;

Or if they want to throw on fail:

或者,如果他们想抛出失败:

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

The generic wrapper method looks like this:

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

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

All three versions have to specify exactly the same three entities, just in different orders, so none are any simpler or any more convenient, and yet the generic version hides what is happening, whereas the "raw" versions each make it clear whether there will be a throw or a null.

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

(This may be irrelevant to you if your example is simplified from your actual code).

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

回答by Samuel

You cannot use the asoperator with a generic type with no restriction. Since the asoperator uses null to represent that it was not of the type, you cannot use it on value types. If you want to use obj as T, Twill haveto be a reference type.

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

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

回答by Cecil Has a Name

It seems like you are just adding a wrapper method for casting to the type the user wants, thus only adding overhead to the execution. For the user, writing

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

int result = Execute<int>();

isn't much different from

int result = (int)Execute();

You can use the outmodifier to write the result into a variable in the caller's scope, and return a boolean flag to tell whether it succeeded:

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

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

回答by Charlie Flowers

Is there a chance that Execute() might return a value type? If so, then you need Earwicker's method for class types, and another generic method for value types. Might look like this:

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

Nullable<T> ExecuteForValueType<T> where T : struct

The logic inside that method would say

该方法内部的逻辑会说

object rawResult = Execute();

Then, you'd have to get the type of rawResult and see if it can be assigned to T:

然后,您必须获取 rawResult 的类型并查看它是否可以分配给 T:

Nullable<T> finalReturnValue = null;

Type theType = rawResult.GetType();
Type tType = typeof(T);

if(tType.IsAssignableFrom(theType))
{
    finalReturnValue = tType;     
}

return finalReturnValue;

Finally, make your original Execute message figure out which T is has (class or struct type), and call the appropriate implementation.

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

Note: This is from rough memory. I did this about a year ago and probably don't remember every detail. Still, I hope pointing you in the general direction helps.

注意:这是粗略的记忆。我大约一年前做过这件事,可能不记得每一个细节。不过,我希望为您指明大方向会有所帮助。

回答by Felix Keil

This small piece of code is an exception safe substitution for the as-keyword:

这段代码是as关键字的异常安全替代:

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

It uses the pattern matching feature introduced with C# 7. Use it, if you don't want to restrict the generic parameter to a reference type

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