接口引用,指定我需要一个实现2个或更多接口的对象

时间:2017-07-04 09:13:48

标签: c# design-patterns interface

让我们说这里有一个过于简单的代码:

class Person
{
    public int age;
    public string name;
    public Person(int age, string name)
    {
        this.age = age;
        this.name = name; 
    }
}
public class MySimpleDatabase
{
    List<Person> people;

    internal List<Person> People
    {
        get
        {
            if(people == null)
            {
                people = new List<Person>();
                people.Add(new Person(24, "ASD"));
                people.Add(new Person(35, "QWE"));
                people.Add(new Person(12, "MNB"));
            }
            return people;
        }
    }
}
public class ProcessPeopleConcrete
{
    public void WriteNames()
    {
        List<Person> people = new MySimpleDatabase().People;
        foreach (var person in people)
        {
            Console.WriteLine(person.name);
        }
    }
}
public class ProcessPeopleInterface
{
    public void WriteNames()
    {
        //question for here.
        IEnumerable<Person> people = new MySimpleDatabase().People;
        foreach (var person in people)
        {
            Console.WriteLine(person.name);
        }
    }
}

这里我有具体的处理器以及基于接口的处理器。这里接口处理器当然更易于维护,但据我所知

   //edited here to clarify

我只能为我需要的变量指定一个类型,在我的情况下,它是IEnumerable<Person>

如果我需要那些同时实现不是一个两个接口 的东西,那么每个都与其他(一个没有实现另一个)?

所以说我需要任何必须实施 ICloneableIEnumerator的集合。在评论中,正确地说我可以定义另一个实现它们的接口。但是,如果我使用预定义的集合,我不能这样做,因为我们将无法抛出任何它们,因为它们显然没有实现我的自定义接口。

在这种情况下,我将为变量people指定哪种类型(在此处注明“问题”)?如果有一个像<IEnumerable, ICloneable> people;这样的变量声明会假设我需要一些实现 IEnumerableICloneable 的东西。但是有没有类似的语言特征,或者它就是我所说的 - 只是虚构的?

2 个答案:

答案 0 :(得分:1)

正如您所知,您不能强制类实现它们不能实现的接口;)

您还注意到接口用于解决特定问题。在一种情况下,他们解决了如何枚举集合,而在另一种情况下,他们解决了如何克隆对象。

从你的问题我认为你希望能够告诉返回的对象解决了这两个问题,你想知道如何在方法合同中告诉它。

您可以通过定义新界面来实现:

public interface ISuperClonableList<T> : IEnumerable<T>, IClonable
{
}

就是这样。

如果列表本身不可克隆,则需要将其包装在实现两个接口的新类中。将实际列表作为构造函数参数传递,并在每个IEnumerable方法实现中调用它。

克隆接口的问题在于它们通常不指定它应该是深度还是浅度克隆。重要的是要知道,如果包含的项目是可变的,它可能会导致很大的问题。

从ReSharper生成的示例:

public class MyListWrapper<T> : ISuperClonableList<T>
{
    private readonly ISuperClonableList<T> _innerList;

    public MyListWrapper(ISuperClonableList<T> innerList)
    {
        _innerList = innerList;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return _innerList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable) _innerList).GetEnumerator();
    }

    public void Add(T item)
    {
        _innerList.Add(item);
    }

    public void Clear()
    {
        _innerList.Clear();
    }

    public bool Contains(T item)
    {
        return _innerList.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _innerList.CopyTo(array, arrayIndex);
    }

    public bool Remove(T item)
    {
        return _innerList.Remove(item);
    }

    public int Count
    {
        get { return _innerList.Count; }
    }

    public bool IsReadOnly
    {
        get { return _innerList.IsReadOnly; }
    }

    public int IndexOf(T item)
    {
        return _innerList.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        _innerList.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _innerList.RemoveAt(index);
    }

    public T this[int index]
    {
        get { return _innerList[index]; }
        set { _innerList[index] = value; }
    }
}

答案 1 :(得分:1)

这可能不是你想要的,但这里有类似于你的概念。我创建了一个接受IEnumerable和IList的Tuple的简单函数,然后你可以向它提供参数:

public static void Foo(Tuple<IEnumerable<int>, IList<int>> complex)
    {
        foreach (var item in complex.Item1)
        {
            Console.WriteLine(item.ToString());
        }

        complex.Item2.Add(9);

    }

一个简单的清单:

 List<int> ints = new List<int>
  {
      1,
      3,
      5,
      7
   };

然后通过首先实例化一个单独的变量来调用该函数,就像我一样,或者将实例化直接写入Foo()函数。

Tuple<IEnumerable<int>, IList<int>> tuple = Tuple.Create((ints as IEnumerable<int>), (ints as IList<int>));
Foo(tuple);

我也对真正的解决方案感兴趣,只要 一个。