我在C#中有以下两个类:
class DbModel{
public List<string> Values {get; set;}
//...other proerties...
}
和
class ViewModel{
public ObservableCollection<string> Values {get; set;}
//...other proerties...
}
我想创建两个类都实现的公用Interface
,因此我可以通过某些方法传递这两个中的任何一个。这有可能吗?我尝试过类似的事情:
public interface IModel{
IEnumerable<string> Values {get; set;}
}
但是,即使List和ObservableCollection<string>
都可以分配给IEnumerable<string>
,这还是行不通的。
有没有解决的办法?最好的解决方法是什么(如果有)?
答案 0 :(得分:2)
C#没有协变返回类型(尽管它们是have been proposed)。因此,您需要使用显式接口实现(如Lasse所述)。
您可能不希望设置Values
属性。如果它是可设置的,那么即使基础IEnumerable<string>
/ ViewModel
仅支持非常特定的类型,任何人都可以设置实现DbModel
的任何类型。
public interface IModel
{
IEnumerable<string> Values { get; }
}
public class ViewModel : IModel
{
public ObservableCollection<string> Values { get; set; }
IEnumerable<string> IModel.Values => Values;
}
答案 1 :(得分:2)
我之前已经尝试过,创建适用于各种实体的漂亮的“域”接口,因此您可以编写在该接口上而不是在域实体上运行的代码,但是您很快就会遇到问题。
对于初学者,当类实现接口时,它必须与接口的成员类型完全匹配。当然,List<T>
和ObservableCollection<T>
都实现了IEnumerable<T>
,但这并不意味着它们都满足该接口成员的声明。
因此,您必须实现该特定类型。例如,您可以使用显式接口实现。但是接口成员既有getter也有setter:
class DbModel : IModel
{
public List<string> Values {get; set;}
IEnumerable<string> IModel.Values
{
get { return Values; }
set
{
Values = ... // now what?
}
}
}
class ViewModel : IModel
{
public ObservableCollection<string> Values {get; set;}
IEnumerable<string> IModel.Values
{
get { return Values; }
set
{
Values = ... // now what?
}
}
}
您可能需要设置器,因为您希望一些通用代码能够分配Values
集合。 IEnumerable<T>
除枚举外,对其他任何事情都没有真正的作用。
因此,您必须将传入的values
转换为与setter中的类相关的类型。例如前者中的Values = values.ToList()
。
然后您有一个呼叫者:
IModel dbModel = new DbModel();
var values = new List<string> { "foo", "bar" };
dbModel.Values = values;
values.Add("baz");
此代码后dbModel.Values
将是什么?提示:它不会包含"baz"
。不要采取这种方法,它会咬你。
忘记通用接口。确定接口应该解决的实际问题,并以其他方式解决。