【问题标题】:Generic method type conversion泛型方法类型转换
【发布时间】:2021-05-05 10:39:51
【问题描述】:

我有这样的事情:

interface IArgument{ ... }

class ArgumentA : IArgument{ ... }

abstract class Parameter<T> where T : class, IArgument{ 
   ...
   abstract decimal GetValue(T args);
   ...
}

class ParameterA : Parameter<ArgumentA>{
   override decimal GetValue(ArgumentA args){
      ...
   }
}

abstract class Calculation{
   List<Parameter<IArgument>> Parameters{get;set;}
   
   decimal FindParameterValue<T>() where T : Parameter<IArgument>{
      ...
   }
}

方法 FindParameterValue 是我遇到问题的地方。它从列表中获取特定类型的第一个参数并返回其值。 现在我得到这个错误: Error CS0311 The type 'ParameterA' cannot be used as type parameter 'T' in the generic type or method 'Calculation.FindParameterValue&lt;T&gt;()'. There is no implicit reference conversion from 'ParameterA' to 'Parameter&lt;IArgument&gt;'. 。 我只想提供一个实现 Parameter 的派生类。 我可以通过这样做来避免它:

public decimal FindParameterValue<T,U>() where T : Parameter<U> where U : class, IArgument

这让我这样称呼它:

FindParameterValue<ParameterA, ArgumentA>();

但我想只使用“ParameterA”类型来调用它。

对不起,如果这已经在某个地方解决了。

提前致谢!

【问题讨论】:

    标签: c# generics constraints


    【解决方案1】:

    约束使用实际类型。如果规则如您所描述的那样有效,则很有可能编写:

    void MyMethod<T>(T myParameter) where T : List<IFruit>{
        myParameter.Add( new Banana() );
    }
    ....
    MyMethod(new List<Apple>());
    

    你最终会得到一个包含香蕉的苹果列表。您可以通过将抽象 Parameter 类更改为协变接口来避免这种情况,即

    interface IArgument { }
    class ArgumentA : IArgument {}
    interface IParameter<out T> where T  :IArgument{ }
    class ParameterA : IParameter<ArgumentA>{}
    
    class Calculation
    {
        void FindParameterValue<T>() where T : IParameter<IArgument>
        { }
    
        void Test()
        {
            FindParameterValue<ParameterA>();
        }
    }
    

    【讨论】:

      【解决方案2】:

      问题在于Parameter&lt;T&gt; 的每个定义都是不同的类型。如果您从抽象类中删除泛型,您将解决您的问题。 Parameter 需要通用吗?你可以改用模式匹配吗?

      虽然意图不是很清楚,但试试下面的代码:

      public interface IArgument { }
      
      public class ArgumentA : IArgument
      {
          public decimal Value { get; }
      }
      
      public abstract class Parameter
      {
          public abstract decimal GetValue(IArgument args);
      }
      
      public class ParameterA : Parameter
      {
          public override decimal GetValue(IArgument args)
          {
              if (args is ArgumentA argA)
              {
                  return argA.Value;
              }
              return 0m;
          }
      }
      
      public abstract class Calculation
      {
          List<Parameter> Parameters { get; } = new List<Parameter>();
      
          public decimal FindParameterValue<T>(IArgument argument) where T : Parameter
          {
              var item = Parameters.OfType<T>().FirstOrDefault();
              if (item != null)
              {
                  return item.GetValue(argument);
              }
              return 0m;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-09
        • 1970-01-01
        • 1970-01-01
        • 2012-11-28
        相关资源
        最近更新 更多