6

我有这样的方法:

private static double ComputePercentage(ushort level, ushort capacity)
{
      double percentage;
      if(capacity == 1)
        percentage = 1;

      // do calculations...
      return percentage;
}

是否可以使它成为像“type T”这样的泛型类型,它可以返回十进制或双精度,具体取决于预期方法的类型(或放入函数的类型?)

我尝试过这样的事情,但我无法让它工作,因为我无法将像“1”这样的数字分配给泛型类型。之后我也尝试使用“where T :”,ushort capacity)但我仍然无法弄清楚。

private static T ComputePercentage<T>(ushort level, ushort capacity)
{
      T percentage;
      if(capacity == 1)
        percentage = 1; // error here

      // do calculations...
      return percentage;
}

这甚至可能吗?我不确定,但我认为这篇文章可能表明我正在尝试做的事情是完全不可能的。


编辑

感谢所有回复的人,很多很好的答案。正如Tomas所指出的,这可能最好通过两种不同的方法来完成。正如TreDubZeddTcKs所指出的,获得我想要的功能的最佳方法是使用可以隐式返回双精度或小数的隐式转换。

4

7 回答 7

5

实际上,您不需要泛型,而是需要重载。但是,您需要通过 IL 支持但 C# 不支持的返回值类型进行重载。

对于每个返回的值类型,我更喜欢两种方法:

static double  ComputePercentageDouble  (ushort level, ushort capacity)
static decimal ComputePercentageDecimal (ushort level, ushort capacity)

替代方法可以是带有隐式强制转换运算符的自定义类型:

decimal decimalPercentage = ComputePercentage( 1, 2 );
double  doublePercentage  = ComputePercentage( 1, 2 );

static DoubleDecimal ComputePercentage( ushort level, ushort capacity ) {
    DoubleDecimal percentage = default( DoubleDecimal );
    if ( capacity == 1 )
        percentage.Number = 1; // error here

    // do calculations...
    return percentage;
}


public struct DoubleDecimal {
    public decimal Number;

    public static implicit operator decimal( DoubleDecimal value ) {
        return value.Number;
    }
    public static implicit operator double( DoubleDecimal value ) {
        return (double)value.Number;
    }
}
于 2010-05-27T22:55:23.073 回答
3

您也许可以使用隐式转换:http: //msdn.microsoft.com/en-us/library/zk2z37d3.aspx

于 2010-05-27T22:27:48.850 回答
3

泛型对于编写适用于任何类型的代码(可能实现某些接口,可以使用 指定where)很有用。但是,如果你想用它们来实现可以返回两种不同数字类型的方法,那就有点不对劲了(只有double实现decimal了一些共享接口才有效)。

您可能应该定义两个不同的方法(例如ComputePercentageComputePercentagePrecise或类似的东西 - 因为您不能使用不同的参数来使用重载)。

可以通过使用类似的东西来解决这个限制(但这对你来说可能过于复杂):

class INumericOps<T> {
  public abstract T One { get; }
  public abstract T Add(T a, T b); 
  // and other operations that you may need
}

// Implementations of numeric operations for decimal and double
class DecimalNumerics : INumericOps<decimal> { ... }
class DoubleNumerics : INumericOps<double> { ... }

然后,您将编写一个方法,将INumericOps<T>其作为类型参数并使用它来执行方法内的所有数学运算:

private static R ComputePercentage<T, R>(ushort level, ushort capacity) 
  where T : INumericOps<R>, where T : new() {
  INumericOps<R> ops = new T(); // Get instance with numeric operations
  T percentage;  
  if(capacity == 1)  
    percentage = ops.One; 

  // Calculations using ops.Add(.., ..) instead of + etc.
  return percentage;  
}  

然后你会这样称呼它:

decimal res = ComputePercentage<DecimalNumerics, decimal>(...);

这是一个不错的技巧,它可能是您可以获得的最佳(类型安全)解决方法。但是,它有点复杂,因此声明两个单独的方法可能是一个更好的主意。

于 2010-05-27T22:45:48.603 回答
1

它不漂亮,但尝试:

percentage = (T)Convert.ChangeType(1, typeof(T));

这至少适用于两者doubledecimal

于 2010-05-27T22:28:34.807 回答
0
private static T ComputePercentage<T>(ushort level, ushort capacity)
{
      if (typeof(T) == typeof(decimal))
        {
            decimal percentage = 1;
            return (T) (object) percentage;
        }

        if (typeof(T) == typeof(double))
        {
            double percentage = 1;
            return (T) (object) percentage;
        }

      throw new NotSupportedExcpetion();
}
于 2010-05-27T22:27:55.043 回答
0

如果您使用的是 C# 4.0,您可以只返回一个dynamic.

于 2010-05-27T22:34:41.150 回答
0

为什么不创建一个百分比类?

class Percent
{
    public Percent(double value)
    {
        this.value = value;
    }

    public double AsDouble()
    {
        return value;
    }

    public decimal AsDecimal()
    {
        return (decimal)value;
    }

    readonly double value;
}

static Percent ComputePercentage(ushort level, ushort capacity)
{
    double percentage = 0;
    if (capacity == 1)
    {
        percentage = 1;
    }

    // calculations

    return new Percent(percentage);
}
于 2010-05-27T23:00:21.283 回答