【问题标题】:Operator as and generic classes运算符 as 和泛型类
【发布时间】:2010-10-16 03:51:09
【问题描述】:

我想做一个方法:

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), nor T.GetType() are possible

    return (T) Execute(); // ok
}

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

【问题讨论】:

    标签: c# .net generics operators on-the-fly


    【解决方案1】:

    你需要添加

    where T : class
    

    到您的方法声明,例如

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

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

    MyClass c = whatever.Execute() as MyClass;
    

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

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

    通用包装方法如下所示:

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

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

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

    【讨论】:

    • 非常感谢您的回答。我将使用它,检查并标记为答案。而且,我还有下一个代码用法: MyClass c = compiler.Execute();我认为这比 MyClass c = compiler.Execute() as MyClass; 更好(我猜里面检查比外面好)
    • 但是外面仍然需要检查——检查是否为空! :) 通过让用户写“as MyClass”,您可以更清楚地表明需要检查 null。
    • 嗯..看来你是对的!我会推荐使用“正常”的 Execute(),但对于最终用户来说,使用这种“异常”的 Execute() 可能会有所帮助,此外还有某种方式的“通用实验”:)
    【解决方案2】:

    您不能将as 运算符与没有限制的泛型类型一起使用。由于as 运算符使用 null 来表示它不是该类型,因此您不能在值类型上使用它。如果您想使用obj as T,T 将拥有作为引用类型。

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

        int result = Execute<int>();
        

        和

        没有太大区别
        int result = (int)Execute();
        

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

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

        【讨论】:

          【解决方案5】:

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

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

          该方法内部的逻辑会说

          object rawResult = Execute();
          

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

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

          最后,让你的原始 Execute 消息弄清楚 T 是哪个(类或结构类型),并调用适当的实现。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-08-06
            • 2016-06-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-28
            相关资源
            最近更新 更多