有一种方法可以处理两种类型的列表

时间:2019-12-17 10:01:56

标签: c#

我有一个ClassAAA,它包含两个属性:

ClassAAA 
{
    public string PropertyX {get;set;}
    public string PropertyY {get;set;}
}

还有一个单独的ClassBBB,它具有相同的属性和一个附加的属性:

ClassBBB 
{
    public string PropertyX {get;set;}
    public string PropertyY {get;set;}
    public string PropertyZ {get;set;}
}

比方说,我都正确初始化了两者,并假设其中有项目:

var aaa = new List<ClassAAA>;
...
var bbb = new List<ClassBBB>;
...

在两个列表上,我必须执行相同的逻辑,例如:

List<ClassAAA> Manipulate(List<ClassAAA> list)
{
    return list.Where(l => PropertyX == ...).ToList();
}
List<ClassBBB> Manipulate(List<ClassBBB> list)
{
    return list.Where(l => PropertyX == ...).ToList();
}

这两个Manipulate方法的代码是相同的,但由于它们基于不同的对象,因此我不得不重复它们。

问题是:在这种情况下,如何避免逻辑重复?理想情况下,将有一种Manipulate方法同时适用于两种类型的列表,但是如何?

PS-还假设我想避免使用反射。

编辑

谢谢大家,缺少的链接实际上是使用IEnumerable,这是一个可行的解决方案:

class Program
{
    static void Main(string[] args)
    {
        var aaa = new List<ClassAAA>();
        aaa = Manipulate(aaa).Cast<ClassAAA>().ToList();
    }        

    public static IEnumerable<IHaveProperties> Manipulate(IEnumerable<IHaveProperties> list)
    {
        return list;
    }
}

public interface IHaveProperties
{
    string PropertyX { get; set; }
    string PropertyY { get; set; }
}

public class ClassAAA : IHaveProperties
{
    public string PropertyX { get; set; }
    public string PropertyY { get; set; }
}

public class ClassBBB : IHaveProperties
{
    public string PropertyX { get; set; }
    public string PropertyY { get; set; }
    public string PropertyZ { get; set; }
}

它也可以在没有接口的情况下工作,并允许ClassBBB从ClassAAA继承。

2 个答案:

答案 0 :(得分:2)

1-定义一个接口并使用您的类实现它:

public interface IHaveProperties
{
    string PropertyX { get; set; }
    string PropertyY { get; set; }
}

public class ClassAAA: IHaveProperties
{
    public string PropertyX { get; set; }
    public string PropertyY { get; set; }
}

public class ClassBBB : IHaveProperties
{
    public string PropertyX { get; set; }
    public string PropertyY { get; set; }
    public string PropertyZ {get;set;}
}

2-定义操作方法:

IEnumerable<IHaveProperties> Manipulate(IEnumerable<IHaveProperties> list)
{
    return list;
}

注意!,您应该在此处使用IEnumerable,而不是List,因为IEnumerable是协变的,因此它将允许您接受集合内的派生类型值。

3-像这样使用它:

Manipulate(new List<ClassAAA>());

有关其他信息,请阅读有关Covariance and Contravariance in Generics

答案 1 :(得分:1)

两个选项:如果ClassBBB是对ClassAAA的扩展,则让ClassBBBClassAAA继承:

class ClassAAA 
{
    public string PropertyX {get;set;}
    public string PropertyY {get;set;}
}

class ClassBBB : ClassAAA
{
    public string PropertyZ {get;set;}
}

然后只需定义一个Manipulate对象即可使用IEnumerable<ClassAAA>个对象:

List<ClassAAA> Manipulate(IEnumerable<ClassAAA> list)
{
    return list.Where(l => PropertyX == ...).ToList();
}

IEnumerable是使用out T定义的,而不是仅使用T定义的,这允许协方差,即泛型参数可以是子类。

由于ClassBBB继承自ClassAAA,因此您可以对两者使用相同的方法。这将编译:

var newList = Manipulate(new List<ClassBBB>());

如果ClassAAAClassBBB非常不同,则让它们实现一个接口:

interface IAnInterface
{
    string PropertyX {get;set;}
    string PropertyY {get;set;}
}

class ClassAAA : IAnInterface
{
    public string PropertyX {get;set;}
    public string PropertyY {get;set;}
}

class ClassBBB : IAnInterface
{
    public string PropertyX {get;set;}
    public string PropertyY {get;set;}
    public string PropertyZ {get;set;}
}

然后定义一个通用的Manipulate方法:

List<T> Manipulate(List<T> list) where T : IAnInterface
{
    return list.Where(l => PropertyX == ...).ToList();
}

并使用如下:

var newList = Manipulate(new List<ClassBBB>());