C# 在列表之间强制转换<;MyType>;和列表<;IMyType>;

C# 在列表之间强制转换<;MyType>;和列表<;IMyType>;,c#,interface,casting,C#,Interface,Casting,我试图解决C#中缺乏对返回类型协方差的支持的问题,如问题和前两个答案所述。在大多数情况下,我在设置强制转换时没有遇到任何问题,但我使用对象/接口列表的一个属性妨碍了我的工作 我需要做什么才能使IFoo.manybar的强制转换工作 public interface IBar { } public interface IFoo { IBar aBar { get; set; } IEnumerable<IBar> manyBars { get; set; } } c

我试图解决C#中缺乏对返回类型协方差的支持的问题,如问题和前两个答案所述。在大多数情况下,我在设置强制转换时没有遇到任何问题,但我使用对象/接口列表的一个属性妨碍了我的工作

我需要做什么才能使
IFoo.manybar
的强制转换工作

public interface IBar
{
}

public interface IFoo
{
    IBar aBar { get; set; }
    IEnumerable<IBar> manyBars { get; set; }
}

class CBar : IBar
{
}

class CFoo : IFoo
{
    public CBar aBar { get; set; }


    //this cast works
    IBar IFoo.aBar 
    {
        get { return aBar; }
        set { aBar = (CBar)value; }
    }

    public List<CBar> manyBars { get; set; }

    //the compiler can't cast either of these
    List<IBar> IFoo.manyBars
    {
        get { return (List<IBar>)manyBars; }
        set { manyBars = (List<CBar>)value; }
    }
}
公共接口IBar
{
}
公共接口IFoo
{
IBar aBar{get;set;}
IEnumerable多条{get;set;}
}
CBar类:IBar
{
}
类CFoo:IFoo
{
公共CBar aBar{get;set;}
//这个演员很好演
伊巴尔·伊福·阿巴尔
{
获取{return aBar;}
设置{aBar=(CBar)值;}
}
公共列表多条{get;set;}
//编译器无法强制转换这两种类型
列出IFoo.manyBars
{
获取{return(List)manyBars;}
设置{manyBars=(列表)值;}
}
}

根据您的需要,您可以创建一个新列表以返回:

return new List<IBar>(manyBars);
返回新列表(多条);

尽管请记住,虽然对象是相同的,但您将检索不同的列表,因此在添加/删除列表中的对象时需要小心。

试试这个。您必须使用System.Linq添加
添加到源文件顶部”

List<IBar> IFoo.manyBars
{
    get { return manyBars.Cast<IBar>().ToList(); }
    set { manyBars = value.Cast<CBar>().ToList(); }
}
列出IFoo.manyBars
{
获取{return manyBars.Cast().ToList();}
set{manyBars=value.Cast().ToList();}
}
请注意,这将在每次访问属性时分配并复制一个新数组。如果这不是您想要的,则应该考虑另一种方法,例如使用类型<代码> IcDeaby 使用
List
还意味着可能有人试图对
anObject.manyBars.Remove(0)
,这将对存储在
anObject
中的列表执行任何操作,因为会返回副本。

您可以制作副本:

get { return manyBars.OfType<IBar>().ToList(); } 
set { manyBars = value.Cast<CBar>().ToList(); }
get{return manyBars.OfType().ToList();}
set{manyBars=value.Cast().ToList();}

但你不能投那个例子。如果您可以强制转换该实例,当我尝试
添加
一个不是CBar的IBar时会发生什么情况。

将我的接口切换到IEnumerable不是问题,这样做可以避免使用Linq进行强制转换导致的移除问题。在某种程度上,类的用户将无法移除项,因为
IEnumerable
接口不公开删除机制。因此,对于用户来说,他们甚至不能尝试删除项目就不那么令人惊讶了。我想我可以接受这一点,因为我正试图封装IFoo/IBar消费者,并且向界面添加添加/删除方法似乎不会带来任何重大问题。CFoo和COtherFoo应用程序的其余部分可以继续使用List/List版本。虽然我可以用我的简单示例类直接执行这个cast
(IEnumerable)manyBars
,但对于我应用程序中更复杂的类,除非我首先将列表转换为如下数组,否则cast将失败:
(IEnumerable)manyBars.ToArray()
。我不知道我的类中是什么导致了这一点,但因为即使在强制转换中有额外的间接操作,我也不会复制对象,我想这并不重要。您最好执行
manyBars.cast()
,因为这不会在每次调用时创建一个全新的列表。它的内存效率更高。我知道这有点脆弱,尽管在实践中,CFoo/CBar和COtherFoo/COtherBar的用户将被隔离。将为前者编写的代码块与使用后者的相关项目共享是最后一刻的需求更改,因此我在追求优雅的过程中受限于重构的范围。如果您希望在出现问题时抛出Cast,请使用Cast。若要将无效项过滤掉,请使用该类型。这几乎是您唯一的选择。不幸的是,我的IFoo消费者需要能够从列表中添加/删除,因此创建新副本不是一个可行的选择。好的,但要小心,因为其他答案也有相同的问题。可以将列表声明更改为“public list manyBars{get;set;}”吗?CBar和COtherBar都包含许多不共享的方法/属性,IBar用户也不关心这些方法/属性,因此我无法更改CFoo/COtherFoo的定义以使用列表,而不必在整个列表中添加强制类型转换(更大)使用CFoo/COtherFoo对象的代码基部分。