我可以在单个泛型类型上指定多个约束吗?

Can I specify multiple constraints on a single generic type?

使用 MVVM 设计模式示例;假设我有一个模型和一个视图模型:

public class UserAccountModel
{
}

public class ViewModel<TModel>
{
    public TModel Model { get; private set; }

    public ViewModel(TModel model)
    {
        this.Model = model;
    }
}

ViewModel<UserAccountModel> = new ViewModel(new UserAccountModel());

但现在我需要添加一些功能来监听模型,以便当它们发生变化时,我可以相应地更新视图:

public class UserAccountModel : INotifyPropertyChanged
{
    //Implementation for INotifyPropertyChanged
}

public class ViewModel<TModel> where TModel : INotifyPropertyChanged
{
    public TModel Model { get; private set; }

    public ViewModel(TModel model)
    {
        this.Model = model;
    }
}

ViewModel<UserAccountModel> = new ViewModel(new UserAccountModel());

这适用于您想要确定 属性 已更改的模型,但现在我还想创建集合模型,它实现了不同的接口:

public class UserAccountCollectionModel : ObservableCollection<UserAccount>
{
}

public ViewModel<UserAccountCollectionModel> vm = new ViewModel<UserAccountCollectionModel>(new UserAccountCollectionModel());

这个错误是因为 UserAccountCollectionModel 没有实现 INotifyPropertyChanged - 相反它实现了 INotifyCollectionChanged

所以我想要的是:

public class ViewModel<TModel> where TModel : INotifyPropertyChanged (or) INotifyCollectionChanged
{
}

据我所知,在 C# 中无法做到这一点,所以我的解决方法是:

public interface IModel
{
}

public class PropertyModel : INotifyPropertyChanged, IModel
{
}

public class CollectionModel : ObservableCollection<PropertyModel>, IModel
{
}

public class ViewModel<TModel> where TModel : IModel
{
}

这对我来说就像大拇指一样刺痛!我认为实现一点也不优雅,因为使用了一个空接口来用于通用约束。

我应该如何创建一个优雅的解决方案来解决这个问题?

如果不了解您打算如何使用您的 ViewModel<T> class,就不可能就正确的实施方式提供建议。但至少可以对 C# 方面发表评论......

就约束而言,允许 可选 的多个约束(即 class 可以实现 either/or)没有任何意义根本。泛型类型中约束的唯一目的是对类型提供编译时限制,以允许泛型类型中的代码使用该类型执行操作。

例如如果您需要 INotifyPropertyChanged,那么在您的泛型类型中,您可以在如此受限的对象(即类型参数类型的任何实例)上订阅 PropertyChanged 事件。

但是,如果允许泛型类型参数简单地实现该接口 某个其他接口,那么您可以在泛型类型中使用它做什么?什么都没有,除了你可以用它做什么,如果它完全不受约束。毕竟, "or" 约束基本上表示可以省略任何一个约束,如果是这种情况,则不能保证例如将出现 PropertyChanged 事件。


没有任何其他信息,我会说这里最好的方法是有两种不同的 view model 类型。 IE。类似于您提出的解决方法,只是您摆脱了 IModelViewModel<T>,而只有 PropertyModel<T>CollectionModel<T>。毕竟,无论如何,两者不太可能以任何有意义的方式重叠。

您有一个选择是放宽对 ViewModel<TModel> class 的约束,但将构造函数设为私有,然后创建两个强类型静态工厂方法来为您执行约束。

像这样:

public class ViewModel<TModel>
{
    public TModel Model { get; private set; }

    public static ViewModel<T> CreateFromObject<T>(T model)
        where T : INotifyPropertyChanged
    {
        return new ViewModel<T>(model);
    }

    public static ViewModel<T> CreateFromCollection<T>(T model)
        where T : INotifyCollectionChanged
    {
        return new ViewModel<T>(model);
    }

    private ViewModel(TModel model)
    {
        this.Model = model;
    }
}