【问题标题】:Refactoring methods with classes implenting IList<T>使用实现 IList<T> 的类重构方法
【发布时间】:2014-12-02 20:08:54
【问题描述】:

我们使用 .NET Framework 3.5 制作了一些类,如下所示:

public class A 
{
    public override string ID { get; set; }
    public override string Name { get; set; }
    private List<B> versionen = new List<B>();
    public List<B> Versionen
    {
        get { return versionen; }
        set { versionen = value; }
    }
}

被其他类中的方法使用,例如

private static void DoSomething(List<A> versioningObj)
{
    foreach (A concretClassAObject in versioningObj)
    {
        foreach (B concretClassAVersionObject in concretClassAObject.Versionen)
        {
        }
    }
}

为了重构这段代码并开发通用方法,我尝试实现以下接口:

public interface VersioningObject<T> : IIDIdentifiable where T : IIDIdentifiable
{
    string Name { get; set; }
    List<T> Versionen { get; set; }
}

public interface IIDIdentifiable
{
    string ID { get; set; }
}

A 类实现“VersioningObject”,B 类实现“IIDDIdentifiable”。新方法如下所示:

private static void DoSomething(List<VersioningObject<IIDIdentifiable>> versioningObj)
{
    foreach (VersioningObject<IIDIdentifiable> concretClassAObject in versioningObj)
    {
        foreach(IIDIdentifiable concretClassAVersionObject in concretClassAObject.Versionen) {
        }
    }
}

我尝试将此方法称为“DoSomething”:

List<A> myList = new List<A>() {new A()};
DoSomething(myList);

并得到以下错误:

  • 无法将“System.Collection.Generic.List”转换为“System.Collection.Generic.List>”
    • DoSomeThing(System.Collections.Generic.List>) 的最佳重载方法匹配有一些无效参数

我该如何解决这个问题。非常感谢您!

【问题讨论】:

  • 你的问题毫无意义。首先什么是B?其次,DoSomething 有 void 返回类型?
  • 如果您将T 限制为IIDIdentifiable,为什么还要使用通用VersioningObject&lt;T&gt;?为什么不让VersioningObject 拥有List&lt;IIDIdentifiable&gt; Versionen
  • 顺便说一句。标题有点误导。您的所有课程都没有实现IList&lt;T&gt;
  • 对不起两个不正确的项目:
  • A 类实现 'Versioning' 并且对该方法的调用必须是:DoSomething(myList);不是 var test = DoSomething(myList); 'B' 只是一个实现 IIDIdentifiable 的类

标签: c# .net-3.5


【解决方案1】:

ListVersioningObject 在它们的泛型参数方面都不是协变的。因此VersioningObject&lt;Child&gt; 不能隐式转换为VersioningObject&lt;Parent&gt;(其中Child 扩展Parent)。即使它是(目前它不能是协变的,因为它接受通用参数作为输入),那么 List&lt;VersioningObject&lt;Child&gt;&gt; 仍然不会隐式转换为 List&lt;VersioningObject&lt;Parent&gt;&gt;

要完成所有这些,您需要进行几个相当基本的重构。

1) VersioningObject 将只需要公开如何读取值,而不是写入它们,从而使其在概念上成为协变的:

public interface VersioningObject<out T> : IIDIdentifiable where T : IIDIdentifiable
{
    string Name { get; }
    List<T> Versionen { get; }
}

2) DoSomething 需要接受 IEnumerable,而不是 ListIEnumerable 是协变的,因为它只允许使用通用参数读取数据。 DoSomething 只需要迭代你所显示的数据,所以这应该没问题。如果您需要实际使用List 特定成员,那么这根本是不可能的。

private static void DoSomething(
    IEnumerable<VersioningObject<IIDIdentifiable>> versioningObj)
{
   //...
}

另外,通用协方差仅在 .NET 4.0 中添加,因此您需要使用该版本的框架才能选择其中任何一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多