C# 您如何退回收藏<;混凝土类型>;作为一个集合<;接口>;?

C# 您如何退回收藏<;混凝土类型>;作为一个集合<;接口>;?,c#,generics,collections,interface,.net-2.0,C#,Generics,Collections,Interface,.net 2.0,我有一个具体类,它包含另一个具体类的集合。我想通过接口公开这两个类,但我很难弄清楚如何将集合成员作为集合成员公开 我目前正在使用.NET2.0 以下代码导致编译器错误: 无法隐式转换类型 将“System.Collections.ObjectModel.Collection”添加到 'System.Collections.ObjectModel.Collection' 已注释的强制转换尝试导致以下编译器错误: 无法转换类型 “System.Collections.ObjectModel.Coll

我有一个具体类,它包含另一个具体类的集合。我想通过接口公开这两个类,但我很难弄清楚如何将集合成员作为集合成员公开

我目前正在使用.NET2.0

以下代码导致编译器错误:

无法隐式转换类型 将“System.Collections.ObjectModel.Collection”添加到 'System.Collections.ObjectModel.Collection'

已注释的强制转换尝试导致以下编译器错误:

无法转换类型 “System.Collections.ObjectModel.Collection”到
通过 引用转换、装箱转换、取消装箱转换、换行 转换或空类型转换

有没有办法将具体类型的集合公开为接口集合,或者我需要在接口的getter方法中创建一个新集合

using System.Collections.ObjectModel;

public interface IBucket
{
    Collection<INail> Nails
    {
        get;
    }
}

public interface INail
{
}

internal sealed class Nail : INail
{
}

internal sealed class Bucket : IBucket
{
    private Collection<Nail> nails;

    Collection<INail> IBucket.Nails
    {
        get
        {
            //return (nails as Collection<INail>);
            return nails;
        }
    }

    public Bucket()
    {
        this.nails = new Collection<Nail>();
    }
}
使用System.Collections.ObjectModel;
公共接口IBucket
{
收集钉子
{
得到;
}
}
INail公共接口
{
}
内部密封类钉子:INail
{
}
内部密封级铲斗:IBucket
{
私人收藏指甲;
收藏IBucket。指甲
{
得到
{
//归还(指甲作为收藏品);
回钉;
}
}
公共桶()
{
this.nails=新集合();
}
}
C#3.0泛型是不变的。如果不创建新对象,则无法执行此操作。C#4.0引入了安全协方差/逆变,它不会改变读/写集合(您的案例)的任何内容。

只需将钉子定义为

Collection<INail>
收藏

为什么不将其作为接口返回,将所有的公共方法都放在接口中,这样就不会有这个问题,而且,如果您以后决定返回另一种类型的Nail类,那么它就可以正常工作。

您使用的是什么版本的.Net

如果您使用的是.net 3.0+,则只能通过使用System.Linq来实现这一点


查看,这为我解决了问题。

您可以使用演员阵容扩展

nails.Cast<INail>()
nails.Cast()

我不能在这里测试它来提供一个更全面的示例,因为我们正在使用.NET 2.0(gripe gripe),但我确实有一个类似的问题

有一个解决方案可能不是您想要的,但可能是一个可接受的替代方案--使用数组

internal sealed class Bucket : IBucket
{
    private Nail[] nails;

    INail[] IBucket.Nails
    {
        get { return this.nails; }
    }

    public Bucket()
    {
        this.nails = new Nail[100];
    }
}

(如果您最终执行了类似的操作,请记住此框架设计指南注意:通常情况下,数组不应作为属性公开,因为它们通常在返回给调用方之前进行复制,而在无辜的属性中进行复制是一项昂贵的操作。)

将其用作属性getter的主体:

List<INail> tempNails = new List<INail>();
foreach (Nail nail in nails)
{
    tempNails.Add(nail);
}
ReadOnlyCollection<INail> readOnlyTempNails = new ReadOnlyCollection<INail>(tempNails);
return readOnlyTempNails;
List tempNails=new List();
foreach(钉子中的钉子)
{
tempNails.Add(钉子);
}
ReadOnlyCollection readonlytempails=新的ReadOnlyCollection(tempails);
返回readonlytempinals;
这是一个有点黑客的解决方案,但它做你想要的

编辑以返回只读集合。请确保在IBucket和Bucket中更新您的类型。

C#不支持通用集合协方差(仅支持数组)。 在这种情况下,我使用适配器类。它只是将所有调用重定向到实际集合,将值转换为所需类型(不需要将所有列表值复制到新集合)。 用法如下所示:

Collection<INail> IBucket.Nails
{
    get
    {
        return new ListAdapter<Nail, INail>(nails);
    }
}

    // my implementation (it's incomplete)
    public class ListAdapter<T_Src, T_Dst> : IList<T_Dst>
{
    public ListAdapter(IList<T_Src> val)
    {
        _vals = val;
    }

    IList<T_Src> _vals;

    protected static T_Src ConvertToSrc(T_Dst val)
    {
        return (T_Src)((object)val);
    }

    protected static T_Dst ConvertToDst(T_Src val)
    {
        return (T_Dst)((object)val);
    }

    public void Add(T_Dst item)
    {
        T_Src val = ConvertToSrc(item);
        _vals.Add(val);
    }

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

    public bool Contains(T_Dst item)
    {
        return _vals.Contains(ConvertToSrc(item));
    }

    public void CopyTo(T_Dst[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

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

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

    public bool Remove(T_Dst item)
    {
        return _vals.Remove(ConvertToSrc(item));
    }

    public IEnumerator<T_Dst> GetEnumerator()
    {
        foreach (T_Src cur in _vals)
            yield return ConvertToDst(cur);
    }

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

    public override string ToString()
    {
        return string.Format("Count = {0}", _vals.Count);
    }

    public int IndexOf(T_Dst item)
    {
        return _vals.IndexOf(ConvertToSrc(item));
    }

    public void Insert(int index, T_Dst item)
    {
        throw new NotImplementedException();
    }

    public void RemoveAt(int index)
    {
        throw new NotImplementedException();
    }

    public T_Dst this[int index]
    {
        get { return ConvertToDst(_vals[index]); }
        set { _vals[index] = ConvertToSrc(value); }
    }
}
收藏IBucket.Nails
{
得到
{
返回新的ListAdapter(钉子);
}
}
//我的实现(不完整)
公共类ListAdapter:IList
{
公共ListAdapter(IList val)
{
_val=val;
}
IList-vals;
受保护的静态T_Src ConvertToSrc(T_Dst val)
{
返回(T_Src)((object)val);
}
受保护的静态T_Dst CONVERTODST(T_Src val)
{
返回(T_Dst)((对象)val);
}
公共作废添加(T_Dst项目)
{
T_Src val=ConvertToSrc(项目);
_val.Add(val);
}
公共空间清除()
{
_vals.Clear();
}
公共布尔包含(TDST项)
{
返回值包含(ConvertToSrc(项目));
}
public void CopyTo(T_Dst[]数组,int arrayIndex)
{
抛出新的NotImplementedException();
}
公共整数计数
{
获取{return\u vals.Count;}
}
公共图书馆是只读的
{
获取{return\u vals.IsReadOnly;}
}
公共布尔删除(TU Dst项目)
{
返回_vals.Remove(ConvertToSrc(项目));
}
公共IEnumerator GetEnumerator()
{
foreach(T_Src cur in _vals)
收益率-收益率转换(cur);
}
IEnumerator IEnumerable.GetEnumerator()
{
返回此.GetEnumerator();
}
公共重写字符串ToString()
{
返回string.Format(“Count={0}”,_vals.Count);
}
公共内部索引(T_Dst项目)
{
返回(ConvertToSrc(项目));
}
公共无效插入(整数索引,T_Dst项目)
{
抛出新的NotImplementedException();
}
公共无效删除(整数索引)
{
抛出新的NotImplementedException();
}
公共T_Dst此[int索引]
{
获取{return ConvertToDst(_vals[index]);}
集合{u vals[index]=ConvertToSrc(value);}
}
}

您可以添加一些泛型。更合身,耦合性更强

public interface IBucket<T> where T : INail
{
    Collection<T> Nails
    {
        get;
    }
}

public interface INail
{
}

internal sealed class Nail : INail
{
}

internal sealed class Bucket : IBucket<Nail>
{
    private Collection<Nail> nails;

    Collection<Nail> IBucket<Nail>.Nails
    {
        get
        {
            return nails; //works
        }
    }

    public Bucket()
    {
        this.nails = new Collection<Nail>();
    }
}

您可能想在这里阅读一系列文章:这是一个解决方案,但如果您只想要一个钉子对象集合,这是一个问题,因为实现INail的每个对象都可以添加到集合中。我会一直坚持到C#4。当然这取决于原始海报。我应该提到这些类是使用XmlSerializer序列化的,这就是为什么集合必须定义为collection而不是collection的原因。@chaospanion C#4有帮助
internal sealed class Bucket : IBucket
{
    private Collection<Nail> nails;

    Collection<INail> IBucket<Nail>.Nails
    {
        get
        {
            List<INail> temp = new List<INail>();
            foreach (Nail nail in nails)
                temp.Add(nail);

            return new Collection<INail>(temp);  
        }
    }

    public Bucket()
    {
        this.nails = new Collection<Nail>();
    }
}