我可以在单个泛型类型上指定多个约束吗?
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。类似于您提出的解决方法,只是您摆脱了 IModel
和 ViewModel<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;
}
}
使用 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。类似于您提出的解决方法,只是您摆脱了 IModel
和 ViewModel<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;
}
}