【问题标题】:Creating a generic function in c# that only works with specific types [duplicate]在 C# 中创建仅适用于特定类型的通用函数 [重复]
【发布时间】:2016-06-23 02:36:39
【问题描述】:

我正在尝试创建一个通用函数来处理我的 2 个模型中的任何一个。请注意,这两个模型具有完全相同的属性...

例如,在下面的代码中,智能感知不知道 T 中有一个名为 Price 的属性,即使 'NewProduct' 和 'OldProduct' 都有这个属性。如何向 VS 指定我希望能够传入的两种类型? IList<NewProduct>, IList<OldProduct>

public static IList<T> GenericFunction<T>(IList<T> objList)
{
    IList<T> filteredData = objList.Where(p => p.Price > 0));
}

【问题讨论】:

标签: c# generics generic-collections


【解决方案1】:

为了使其工作,您需要在这两种产品类型中实现一个公共基类或一个公共接口。

public interface IProduct
{
    string Name { get; set; }
    decimal Price { get; set; }
}

然后你可以添加一个generic type constraint

public static IList<P> GenericFunction<P>(IList<P> objList)
    where P : IProduct // Here you can specify either the base class or the interface.
{
    return objList
        .Where(p => p.Price > 0)
        .ToList();
}    

现在 C# 知道泛型类型 P 具有 NamePrice 属性。


注意:您可以只键入参数列表和返回类型为IList&lt;IProduct&gt;;但是,IList&lt;OldProduct&gt;IList&lt;NewProduct&gt; 与它分配兼容。


更新:如果泛型类型具有默认构造函数(即具有空参数列表或根本没有显式构造函数声明的构造函数),则可以实例化泛型类型。然后您需要将new() 添加到泛型类型约束中:

where P : IProduct, new()

然后您可以简单地创建一个新对象:

P newObject = new P();

【讨论】:

  • 你应该从你的接口声明中删除public。接口不声明其成员的访问级别,任何实现此接口的类都需要将成员声明为公共的。接口 == 合约。
  • @OlivierJacot-Descombes 感谢您为我解决这个问题。你说的都有道理。我遇到了一个场景,我需要在这个函数中实例化一个新的 P 对象。这不会限制我使用您上面发布的通用函数吗?或者我仍然可以使用返回 IList 的简单函数使其工作吗?我觉得既然我需要实例化一个新的 P 对象,然后将其添加到返回值中,这不是使用 InterfaceorBaseClass 我唯一选择的通用函数吗?
  • @OlivierJacot-Descombes 澄清我之前的评论:我注意到我必须执行以下操作: P ret = (P)Activator.CreateInstance(typeof(P));为了实例化 P 的新对象并将其添加到我的 IList

    retVal?这是否需要我使用通用函数?我不相信还有其他解决方法吗?

  • 我添加了关于如何实例化泛型类型的说明。
【解决方案2】:

你可以使用 where 泛型约束https://msdn.microsoft.com/en-us/library/bb384067.aspx

您需要一些它们都扩展/实现的通用基类或接口。您可以定义多个约束,但它们必须是相关的。

interface IProduct
{
    double Price { get; }
}

public static IList<T> GenericFunction<T>(IList<T> objList) where T : IProduct
{
    IList<T> filteredData = objList.Where(p => p.Price > 0));
}

【讨论】:

  • 这对我来说开始有意义了,我相信这是正确的答案。但是,如果我使用接口,那么使泛型函数正确没有意义?只需制作一个接受我的界面的函数。有意义吗?
  • 不一定正确,这样做的好处是返回值是实际类型(例如 List)。仅使用接口将始终返回 List.
【解决方案3】:

您应该为此使用接口。使用您需要的属性创建一个接口:

public interface MyInterface
{
    string Name { get; set; }
    string Color { get; set; }
}

这些属性应该是您的模型共享的属性。然后在你的模型中你必须实现接口:

public class MyModel : MyInterface

然后制作你的方法:

public void MyFunction(List<MyInterface> myModel)

【讨论】:

    【解决方案4】:

    两种类型都需要相同的接口或公共基类,这里称为ProductBase。然后,您可以使用带有 where 关键字的通用约束:

    public static IList<T> GenericFunction<T>(IList<T> objList) 
      where T : ProductBase
    {
        IList<T> filteredData = objList.Where(p => p.Price > 0));
    }
    

    如果ProductBase 定义了一个属性Price,则此方法有效。

    【讨论】:

      【解决方案5】:

      您应该研究抽象类、扩展和多态性。使用价格变量创建一个抽象类,然后从中扩展您的两个类。然后使用抽象类作为参数。

      【讨论】:

      • 两个模型都从中实现的接口怎么样?
      • 这也有效。请参阅@ventiseis 答案
      猜你喜欢
      • 2022-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多