C# - 接受任何类型的 IEnumerable 作为参数

C# - Accept IEnumerable of any type as parameter

我有这个构造函数,它应该接受任何类型的任何 IEnumerable,并尝试将值转换为所需的类型

public ChartData(IEnumerable<dynamic> labels, IEnumerable<dynamic> values)
            {
                this.values = values.Select(x=>(float)Convert.ToString(x));
                this.labels = labels.Select(x=>(string)Convert.ToString(x));
            }

当我调用这个构造函数时,我可以传递字符串类型的 ienumerables,但不能传递 int 或 float 我如何制作一个构造函数来接受任何类型的 ienumerables 而不会产生大量的重载?

如果您接受任何类型,其中还包括 IEnumerable<User>IEnumerable<Car>,您希望如何将它们转换为浮点数和字符串?拥有一个封装浮点数和字符串值的对象会好得多,为此使用一个接口。例如,有一个这样的界面:

public interface IChartItem
{
    float Value { get; set; }
    string Label { get; set; }
}

一个例子class:

public class Foo : IChartItem
{
    public int MyProperty { get; set; }
    public string Name { get; set; }
    
    public float Value => (float)MyProperty;
    public string Label => Name;
}

现在您的函数可以是带有约束的通用函数:

public void ChartData<T>(IEnumerable<T> items)
    where T : IChartItem
{
    this.values = items.Select(x => x.Value);
    this.labels = items.Select(x => x.Label);
}

备选方案

您还可以传入您的对象以及几个 Func 参数来获取值和标签。例如:

public void ChartData<T>(IEnumerable<T> items, 
    Func<T, float> valueSelector, 
    Func<T, string> labelSelector)
{
    this.values = items.Select(x => valueSelector(x));
    this.labels = items.Select(x => labelSelector(x));
}

并像这样使用它:

ChartData(foos, f => (float)f.MyProperty, f => f.Name);

如果您不关心类型,请使用非泛型版本 IEnumerable(这是 IEnumerble<T> 的基本接口):

public ChartData(IEnumerable labels, IEnumerable values)
{
      // x is of type Object for both lines.
      this.values = values.Select(x=>(float)Convert.ToSingle(x));
      this.labels = labels.Select(x=>(string)Convert.ToString(x));
}

注意

  • 你失去了所有类型安全性——有人可以轻松地将文件列表或其他一些随机类型作为参数之一传递
  • 如果由于装箱成本而处理值类型,一般来说泛型版本更可取。幸运的是,在您的情况下,您仍然需要盒装价值或 Convert.

我个人只接受 IEnumerable<float>(或者 double)和 IEnumerable<String> 作为参数 - 此方法的调用者将有更多知识来选择所需的 fields/conversion比我的代码试图猜测他们传入的类型。如果某些“任何数字类型”将是所需的输入,我会检查 Is there a constraint that restricts my generic method to numeric types? 并实现所有变体,而不是使用 dynamic 回退到运行时反射或非通用版本缺乏类型安全。