处理泛型接口的非泛型部分



考虑以下代码:

public interface IStuff<T>
{
    IList<T> Items { get; set; }
    bool IsExpanded { get; set; }
}
public interface IBar
{
    string Name { get; set; }
}
public interface IFoo : IBar, IStuff<IBar>
{
}
public class MyClass : IFoo 
{
    public Name {get;set;
    public IList<IBar> Items { get; set;}
    bool IsExpanded { get; set; }
}

当我使用这个时,我实际上要做的是用IFoo的实例填充MyClass.Items,这是允许的,因为IFoo实现了IBar,所以一切都很好。

然而,有一种方法,我在一个控件内工作,它不知道也不应该知道IBar。它只需要知道IStuff<>,特别是有一个列表和一个属性。

当我使用Items时,我将检测项目是否像这样实现IStuff

public void ProcessItems( object item )
{
    IStuff<object> stuff = item as IStuff<object>;
    stuff.IsExpanded = true;
    foreach( var childItem in stuff.items )
    {
        ProcessItems( childItem );
    }
}

这里的问题是,转换成IStuff<object>现在不工作,它返回null。我想做的是只使用接口的通用部分,我不关心T是什么。

问题是如何替换

IStuff<object> stuff = item as IStuff<object>;

以便我可以使用在IStuff<>接口中声明的项?

听起来你需要在你的接口IStuff上进行协方差。但是,由于IList<T>不是协变的,您可以使用支持协变的接口,例如IEnumerable<T>,其中自。net 4.0以来是协变的:

public interface IStuff<out T>
{
    IEnumerable<T> Items { get; set; }
    bool IsExpanded { get; set; }
}

现在可以将IStuff<IBar>的实例强制转换为IStuff<object>

您可以将IStuff拆分为非泛型和泛型部分(从非泛型部分继承),然后仅处理代码中的非泛型部分吗?例如

public interface IStuff
{
    IsExpanded { get; set; }
}
public interface IStuff<T> : IStuff
{
    IList<T> Items { get; set; }
}

如果您不介意反射,您可以读取属性并将其强制转换为IEnumerable:

var listType = item.GetType().GetProperty("Items");
var enumerable = (IEnumerable)(listType.GetValue(item));

同样,您可以设置扩展标志

相关内容

  • 没有找到相关文章

最新更新