You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为C#属性指定实现多个接口的派生类型?

解决方法

要给属性指定同时实现多个接口的类型,有几种实用的方式,你可以根据场景选择:

1. 定义组合接口(最推荐)

直接创建一个继承自你需要的两个接口的新接口,用这个接口作为属性类型。既能保持类型安全,又能灵活接受任何满足这两个接口的类型。

示例代码:

// 定义组合接口,继承两个目标接口
public interface ICollectionWithChangeNotifications<T> : ICollection<T>, INotifyCollectionChanged
{
    // 无需添加额外成员,自动继承两个接口的所有成员
}

public class FooBar
{
    public ObservableCollection<string> Bar { get; } = new();
    
    // 用组合接口作为属性类型
    public ICollectionWithChangeNotifications<string> MyCollection { get; } = new ObservableCollection<string>();
    
    public void Main(string[] args)
    {
        Foo(MyCollection);
    }

    public void Foo<T>(T collection) where T : ICollection<string>, INotifyCollectionChanged
    {
        collection.Add("bar");
        collection.CollectionChanged += Collection_CollectionChanged;
    }

    private void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        throw new NotImplementedException();
    }
}

ObservableCollection<T>本身就同时实现了ICollection<T>和INotifyCollectionChanged,所以可以直接赋值给这个属性。后续如果要替换成其他满足条件的集合类型,只要它实现了ICollectionWithChangeNotifications<T>接口即可。

2. 将类改为泛型类

如果不想新增接口,可以把FooBar改成泛型类,通过泛型约束限定属性类型必须满足两个接口。

示例代码:

// 泛型类,约束泛型参数必须同时实现两个接口
public class FooBar<TCollection> where TCollection : ICollection<string>, INotifyCollectionChanged
{
    public ObservableCollection<string> Bar { get; } = new();
    
    // 用泛型参数作为属性类型
    public TCollection MyCollection { get; }

    // 通过构造函数注入具体的集合实例
    public FooBar(TCollection collection)
    {
        MyCollection = collection;
    }

    public void Main(string[] args)
    {
        Foo(MyCollection);
    }

    public void Foo<T>(T collection) where T : ICollection<string>, INotifyCollectionChanged
    {
        collection.Add("bar");
        collection.CollectionChanged += Collection_CollectionChanged;
    }

    private void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        throw new NotImplementedException();
    }
}

// 实例化时指定具体的集合类型
var fooBar = new FooBar<ObservableCollection<string>>(new ObservableCollection<string>());

这种方式适合需要在多个场景复用FooBar类,且每个实例可能使用不同集合类型的情况。

3. 不推荐:使用dynamic类型(失去类型安全)

如果不在乎编译时的类型检查,可以用dynamic作为属性类型,但运行时如果赋值的类型不满足两个接口,会直接抛出异常,仅适合临时测试或特殊场景:

public class FooBar
{
    public ObservableCollection<string> Bar { get; } = new();
    
    public dynamic MyCollection { get; } = new ObservableCollection<string>();
    
    // 后续代码保持不变
}

内容的提问来源于stack exchange,提问作者user8934733

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 18:33:13