简体   繁体   English

使用接口类型作为通用

[英]Using Interface Type as generic

I have a class which must implement the following property 我有一个必须实现以下属性的类

public ICollection<IType> Items
{
     get { return this.items;}
}

My question is how to implement this when the type of this.items is a List<MyType> where MyType implements IType . 我的问题是当this.items的类型是List<MyType>时,如何实现这一点,其中MyType实现了IType I need to ensure the following: 我需要确保以下内容:

  1. Unecessary enumeration of the list is avoided if possible 如果可能,避免不必要的列表枚举
  2. That the class can internally treat the elements of this.items as their concrete type 该类可以在内部将this.items的元素视为其具体类型
  3. That external callers may add and remove elements to this collection 外部调用者可以向此集合添加和删除元素

Thanks in advance. 提前致谢。

Like Paul mentioned, you can't have both #2 and #3. 就像保罗提到的那样,你不能同时拥有#2和#3。 You'll have to pick one or the other, or expose the concrete type to external callers. 您必须选择其中一个,或将具体类型暴露给外部呼叫者。 But, for your actual requirement, your best bet is to store your collection as a List internally, and just use a method when you need to get a member by the concrete type. 但是,根据您的实际需求,您最好的选择是将您的集合作为List存储在内部,并在需要按具体类型获取成员时使用方法。 Something like this: 像这样的东西:

private List<IType> items = new List<IType>();

private TType GetItem<TType>(int index)
    where TType : IType
{
    return (TType)items[index];
}

public ICollection<IType> Items
{
    get
    {
        return this.items;
    }
}

As pointed out by @PaulPhillips in the comments to this question: 正如@PaulPhillips在对这个问题的评论中指出的那样:

Requirements (2) and (3) are contradictory. 要求(2)和(3)是矛盾的。

One approach is to change the type of Items to IEnumerable<IType> and have another property of ICollection<MyType> . 一种方法是将Items的类型更改为IEnumerable<IType>并具有ICollection<MyType>另一个属性。 This will mean some redesign but clearly I was going about this wrong anyway. 这将意味着一些重新设计但显然我无论如何都要犯这个错误。

Thanks! 谢谢!

Either declare this.items as a List<IType> if you want to expose it as ICollection<IType> and thus allowing external callers to add ITypes that are not MyTypes . 无论是声明this.items作为一个List<IType>如果你想公开为ICollection<IType>从而允许外部呼叫者添加ITypes不在MyTypes

Internally work like this on the items of the list 在列表中的项目内部工作

var myObj = this.items[i] as MyType;
if (myObj == null) {
    work with this.items[i] and treat it as a IType
} else {
    work with myObj which is a MyType
}

OR 要么

declare the public property as 将公共财产声明为

public ICollection<MyType> Items { get return this.items; } }

and thus allow external callers to add only items of type MyType . 因此允许外部调用者只添加MyType类型的项目。

I am sorry, but you cannot fulfill conditions (2) and (3) at the same time 对不起,但你不能同时满足条件(2)和(3)


UPDATE UPDATE

Another option is to only allow external callers to get items of the list but not to add items, by using an indexer having only a getter. 另一种选择是仅允许外部呼叫者通过使用仅具有吸气剂的索引器来获取列表中的项目而不是添加项目。

public IType this[int i]
{
    get { return this.items[i]; }
}

an external caller can then access items like this 然后外部呼叫者可以访问这样的项目

var obj = new ClassImplementingThisStuff();
int i = 5;
IType x = obj[i];

Also add a count property 还要添加count属性

public int Count { 
    get { return this items.Count; }
}

This solution avoids unnecessary enumeration. 该解决方案避免了不必要的枚举。

How about Items being IEnumerable<IType> ? ItemsIEnumerable<IType>怎么样? IEnumerable is covariant so the code would just work with no changes. IEnumerable是协变的,所以代码只能在没有变化的情况下工作。 On the other hand, you could have another, dedicated method to add elements to the internal list. 另一方面,您可以使用另一种专用方法将元素添加到内部列表中。

class MainClass
{
  public static void Main()
  {
    ShowMeHowToDoIt show = new ShowMeHowToDoIt();
    show.Add( new TheType() );

    foreach ( var item in show.Items )
    {
   Console.WriteLine( item );
    }     
  }
}

public class ShowMeHowToDoIt
{
  private List<TheType> items = new List<TheType>();

  public void Add( TheType item ) { items.Add( item ); }

  public IEnumerable<IType> Items
  {
    get { return items; }
  }
}

public interface IType { }

public class TheType : IType { }

I think the points in the comments about this being possibly a bad design are valid, however you can still do something like this and get away with it: 我认为关于这个可能是一个糟糕的设计的评论中的要点是有效的,但你仍然可以做这样的事情并逃脱它:

interface IFruit
{
    string Name { get; }
    string SerialNumber { get; }
}

class Apple : IFruit
{

    private string _serial = Guid.NewGuid().ToString();

    public string Name {
        get {
            return "Apple";
        }
    }

    public string SerialNumber {
        get { return _serial; }
    }
}


class AppleBasket : IEnumerable<IFruit>
{
    private List<Apple> _items = new List<Apple>();

    public void Add(Apple apple) {
        _items.Add(apple);
    }


    public IEnumerator<IFruit> GetEnumerator() {
        return _items.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return _items.GetEnumerator();
    }
}

/******************/

AppleBasket basket = new AppleBasket();
Apple apple1 = new Apple();
basket.Add(apple1);

Apple apple2 = new Apple();
basket.Add(apple2);

foreach (IFruit fruit in basket) {
    Console.WriteLine(fruit.SerialNumber);
}

I would recommend you rethink your approach though. 建议你重新考虑,虽然你的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM