为什么这种隐式转换是不可能的?
Why is this implicit cast is not possible?
鉴于 类 和下面的接口,我想知道为什么隐式转换:
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
不可能。我试过了
public interface ISomeModelAbstract<out T> where T: IBasicModel
但是我不能使用 GetById
和 GetAll
方法。我感谢任何帮助或提示。谢谢。
public interface IBasicModel {
string _id { get; set; }
}
public class SomeModel: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
public interface ISomeModelAbstract<T> where T: IBasicModel
{
bool Save(T model);
T GetById(string id);
IEnumerable<T> GetAll();
bool Update(string id, T model);
bool Delete(string id);
}
public abstract class SomeModelAbstract<T> : ISomeModelAbstract<T> where T : IBasicModel
{
public bool Save(T model)
{
throw new System.NotImplementedException();
}
public T GetById(string id)
{
throw new System.NotImplementedException();
}
public IEnumerable<T> GetAll()
{
throw new System.NotImplementedException();
}
public bool Update(string id, T model)
{
throw new System.NotImplementedException();
}
public bool Delete(string id)
{
throw new System.NotImplementedException();
}
}
public interface IConcreteClass: ISomeModelAbstract<SomeModel> { }
public class ConcreteClass: SomeModelAbstract<SomeModel>, IConcreteClass { }
由于协方差问题,这不起作用。考虑这个示例代码。
public class SomeModel2: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
之后,您可以将 SomeModel2 的某些对象传递给 x 的 Save 方法,显然,这是不可行的。
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
var m = new SomeModel2();
x.Save(m);
为了防止这种情况发生,您应该隐含地告诉您您只在 return(out)的地方使用您的通用类型,而不是在输入中。例如:
public interface ISomeModelAbstract<out T> where T: IBasicModel
很遗憾,执行此操作后,您无法在 ISomeModelAbstract 接口中使用 Save 和 Update 方法。因为他们在参数(输入)的地方用了T。
有关详细信息,请参阅下面的 link:http://tomasp.net/blog/variance-explained.aspx/
另一个答案已经描述了它在当前状态下不起作用的原因。我想补充一点,在这种情况下,将接口(或两者)的协变或逆变部分提取到单独的接口中通常很有用。例如:
// covariant part, T is used only as return value
// ISomeModelRead is not the best name of course
public interface ISomeModelRead<out T> where T : IBasicModel {
T GetById(string id);
IEnumerable<T> GetAll();
}
// the rest of interface, also implementing covariant part
public interface ISomeModelAbstract<T> : ISomeModelRead<T> where T : IBasicModel {
bool Save(T model);
bool Update(string id, T model);
bool Delete(string id);
}
现在一切都一样了,除了你可以做:
ISomeModelRead<IBasicModel> x = new ConcreteClass();
x.GetAll();
x.GetById("id");
鉴于 类 和下面的接口,我想知道为什么隐式转换:
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
不可能。我试过了
public interface ISomeModelAbstract<out T> where T: IBasicModel
但是我不能使用 GetById
和 GetAll
方法。我感谢任何帮助或提示。谢谢。
public interface IBasicModel {
string _id { get; set; }
}
public class SomeModel: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
public interface ISomeModelAbstract<T> where T: IBasicModel
{
bool Save(T model);
T GetById(string id);
IEnumerable<T> GetAll();
bool Update(string id, T model);
bool Delete(string id);
}
public abstract class SomeModelAbstract<T> : ISomeModelAbstract<T> where T : IBasicModel
{
public bool Save(T model)
{
throw new System.NotImplementedException();
}
public T GetById(string id)
{
throw new System.NotImplementedException();
}
public IEnumerable<T> GetAll()
{
throw new System.NotImplementedException();
}
public bool Update(string id, T model)
{
throw new System.NotImplementedException();
}
public bool Delete(string id)
{
throw new System.NotImplementedException();
}
}
public interface IConcreteClass: ISomeModelAbstract<SomeModel> { }
public class ConcreteClass: SomeModelAbstract<SomeModel>, IConcreteClass { }
由于协方差问题,这不起作用。考虑这个示例代码。
public class SomeModel2: IBasicModel {
public string _id { get; set; }
/* some other properties! */
}
之后,您可以将 SomeModel2 的某些对象传递给 x 的 Save 方法,显然,这是不可行的。
ISomeModelAbstract<IBasicModel> x = new ConcreteClass();
var m = new SomeModel2();
x.Save(m);
为了防止这种情况发生,您应该隐含地告诉您您只在 return(out)的地方使用您的通用类型,而不是在输入中。例如:
public interface ISomeModelAbstract<out T> where T: IBasicModel
很遗憾,执行此操作后,您无法在 ISomeModelAbstract 接口中使用 Save 和 Update 方法。因为他们在参数(输入)的地方用了T。
有关详细信息,请参阅下面的 link:http://tomasp.net/blog/variance-explained.aspx/
另一个答案已经描述了它在当前状态下不起作用的原因。我想补充一点,在这种情况下,将接口(或两者)的协变或逆变部分提取到单独的接口中通常很有用。例如:
// covariant part, T is used only as return value
// ISomeModelRead is not the best name of course
public interface ISomeModelRead<out T> where T : IBasicModel {
T GetById(string id);
IEnumerable<T> GetAll();
}
// the rest of interface, also implementing covariant part
public interface ISomeModelAbstract<T> : ISomeModelRead<T> where T : IBasicModel {
bool Save(T model);
bool Update(string id, T model);
bool Delete(string id);
}
现在一切都一样了,除了你可以做:
ISomeModelRead<IBasicModel> x = new ConcreteClass();
x.GetAll();
x.GetById("id");