【问题标题】:How to make a Generic average method, so that you can put any type in it?如何制作通用平均方法,以便您可以将任何类型放入其中?
【发布时间】:2019-10-18 11:03:49
【问题描述】:

我尝试制作一个通用平均方法。这样该方法就可以与任何类型进行交互。但 any 类型的值也必须是通用的。这样您就可以拥有以下类型:int、float、decimal。

我是这样尝试的:

public class Calculator<T>
    {
        public T Average(List<T>items, Func<T, T>  getValue )
        {

            T sum = 0 ;

            foreach (var item in items)
            {
                sum += getValue(item);
            }

            return (T) Convert.ChangeType(sum / items.Count(), typeof(T));
        }
    }
}

我有一个这样的示例类:

public  class Product<T>
    {

        public T Weight { get; set; }

    }

但是我已经在这一行得到了一个错误:

   T sum = 0 ;

无法将类型“int”隐式转换为“T”

和程序类:


            var listProducts = new List<Product<int>> { 
                    new Product<int>{ Weight = 1},
                    new Product<int> { Weight = 2},
                    new Product<int> { Weight = 87}
            };
            var calc2 = new Calculator<Product<int>>();
            var averageWeight = calc2.Average(listProducts, p => p.Weight);

            Console.WriteLine($"Average weight is: {averageWeight}" );

我现在是这样的:

public class Calculator<T> where T: class
    {
        public T Average(List<T>items, Func<T, T>  getValue )
        {

            T sum = default(T);

            foreach (var item in items)
            {
                sum += getValue(item);
            }

            return (sum / items.Count());
        }
    }

但我得到了这个错误:

'+=' cannot be applied to operands of type 'T' and 'T'

在这一行:

sum += getValue(item);

【问题讨论】:

  • 请看我更新的答案

标签: c# generics delegates


【解决方案1】:

尝试声明每个关注的默认值

T sum = default(T);

如果您只使用数值类型,使用泛型类型约束进行计算也很有意义

where S : struct, IComparable, IComparable<S>, IConvertible, IEquatable<S>, IFormattable

另外,您将p =&gt; p.Weight 传递为Func&lt;T, T&gt; getValue,这是不正确的,您应该在Func&lt;T, TResult&gt; 中为返回值声明额外的泛型类型参数,目前您接受和返回相同的类型

最后,我通过添加一个额外的通用参数并将sum 设置为dynamic 来使您的 sn-p 工作,以避免编译时错误

public class Program
{
    static void Main(string[] args)
    {
        var listProducts = new List<Product<int>> {
            new Product<int> { Weight = 1},
            new Product<int> { Weight = 2},
            new Product<int> { Weight = 87}
        };
        var calc2 = new Calculator<Product<int>, int>();
        var averageWeight = calc2.Average(listProducts, p => p.Weight);

        Console.WriteLine($"Average weight is: {averageWeight}");
    }
}

public class Calculator<T, S> where S : struct, IComparable, IComparable<S>, IConvertible, IEquatable<S>, IFormattable
{
    public S Average(List<T> items, Func<T, S> getValue)
    {
        dynamic sum = default(S);

        foreach (var item in items)
        {
            var result = getValue(item);
            sum += result;
        }

        return (S)Convert.ChangeType(sum / items.Count, typeof(S));
    }
}

打印出来

平均体重:30

在您的 sn-p Product&lt;int&gt; 作为Calculator 的泛型类型参数和intProduct&lt;T&gt; 的泛型类型参数中,您不能将它们都用作getValue 中的一个参数并返回来自Average

【讨论】:

  • 啊,谢谢。很不错。但是你为什么要使用结构?而不是上课?
  • 啊,好吧,当然,因为十进制是一种值类型,就像一个结构。类是通过引用。不是吗?
  • @mightycodeNewton 是的,你是对的,因为对于非值类型,当尝试求和或除法时,你会得到一个异常。当然,您可以覆盖这些运算符,但这是一个额外的主题:)
猜你喜欢
  • 1970-01-01
  • 2014-11-10
  • 2015-04-18
  • 1970-01-01
  • 2020-07-22
  • 2020-12-12
  • 1970-01-01
  • 2018-10-23
  • 1970-01-01
相关资源
最近更新 更多