出于某种原因,我正在努力通过使用通用基类来实现泛型接口中的属性,如下所示:
public interface IParent<TChild> where TChild : IChild
{
TChild Child { get; }
}
public interface IChild { }
然后我有一个基类:
public class ParentBase<TChild> : IParent<TChild> where TChild : IChild
{
private TChild _child;
public ParentBase(TChild child)
{
this._child = child;
}
#region IParent<TChild> Members
public TChild Child
{
get { return _child; }
}
#endregion
}
现在我有一个新的Parent Derivative和Child对象,如下所示:
public class MyChild : IChild { }
public class MyParent : ParentBase<MyChild>, IParent<IChild>
{
public MyParent(MyChild child)
: base(child)
{
}
}
我想实例化它并获取抽象(接口类型)以传递给消费者,如下所示:
IParent<IChild> parent = new MyParent(new MyChild());
但由于某种原因,我无法正确实现TChild,即使我在ParentBase上定义了属性public TChild Child
,编译器也表示它没有实现,即使我尝试显式实现。
正如您所看到的,约束一直到基类。
答案 0 :(得分:4)
您从ParentBase<MyChild>
和IParent<IChild>
派生MyParent。
IParent<IChild> { IChild Child{get; } }
添加显式实现将允许您的原始代码编译
public class MyParent : ParentBase<MyChild>, IParent<IChild>
{
public MyParent(MyChild child)
: base(child)
{
}
#region Implementation of IParent<IChild>
IChild IParent<IChild>.Child
{
get { return base.Child; }
}
#endregion
}
如果你也像这样做IParent协变:
public interface IParent<out TChild> where TChild : IChild
{
TChild Child { get; }
}
然后你现在可以做到这一点
IParent<IChild> parent = new MyParent(new MyChild());
或
ParentBase<MyChild> parent2 = new MyParent(new MyChild());
和
IParent<IChild> parent3 = parent2;
正如@svick在答案中指出的那样,通过协方差,你可以通过不从IParent<IChild>
派生并删除显式接口实现来简化。
答案 1 :(得分:3)
这正是通用方差有用的地方。如果您将IParent
interfce标记为协变:
public interface IParent<out TChild> where TChild : IChild
并从IParent<IChild>
MyParent
的显式推导
public class MyParent : ParentBase<MyChild>
然后可以将MyParent
视为已实施IParent<IChild>
。例如,以下代码可以工作:
MyParent parent = new MyParent(new MyChild());
IParent<IChild> iParent = parent;
答案 2 :(得分:0)
如果消费者需要使用孩子而不是孩子,你能否摆脱通用界面?
public interface IParent
{
public IChild Child { get; }
}
然后你的继承工作得很好
public class ParentBase<TChild> : IParent where TChild : IChild
{
public IChild Child { get { return myChild; } }
}
和
public class MyParent : ParentBase<MyChild> // already implements IParent by the base doing so.
{
}