我有一个由几个"级别组成的应用程序"元素。有些元素是0..N子元素的父元素,它们本身是0..N其他元素的父元素。顶级类型没有父级,底级元素没有子级。
换句话说,设三种类型:A,B和C. A的实例是B的多个实例的父实例,它们本身是C的多个实例的父实例。每个实例也有一个(强类型)引用到它的父母。
我在父类中有几个相同的方法,比如AddChild,RemoveChild,GetChildIndex等。我想为所有父类创建一个基类,以便不为每个父类复制这些方法。
这个想法是,当从父基类派生时,你必须根据父类的类型提供子类的类型。
到目前为止,我已经提出了这种过于复杂的设计:
public interface IChild<TParent> where TParent : ParentBase<IChild<TParent>>
{
TParent Parent { get; set; }
}
public class ParentBase<TChild> where TChild : IChild<ParentBase<TChild>>
{
public List<TChild> Children;
}
public class A : ParentBase<B>
{
}
public class B : ParentBase<C>, IChild<A>
{
}
public class C : IChild<B>
{
}
但是我收到了编译错误:
Error CS0311 The type 'TemplateTest.IChild<TParent>' cannot be used as type parameter 'TChild' in the generic type or method 'ParentBase<TChild>'. There is no implicit reference conversion from 'TemplateTest.IChild<TParent>' to 'TemplateTest.IChild<TemplateTest.ParentBase<TemplateTest.IChild<TParent>>>'. Kbd2 C:\dev\Kbd2\TemplateTest.cs 6 Active
Error CS0311 The type 'TemplateTest.ParentBase<TChild>' cannot be used as type parameter 'TParent' in the generic type or method 'IChild<TParent>'. There is no implicit reference conversion from 'TemplateTest.ParentBase<TChild>' to 'TemplateTest.ParentBase<TemplateTest.IChild<TemplateTest.ParentBase<TChild>>>'. Kbd2 C:\dev\Kbd2\TemplateTest.cs 11 Active
Error CS0311 The type 'TemplateTest.B' cannot be used as type parameter 'TChild' in the generic type or method 'ParentBase<TChild>'. There is no implicit reference conversion from 'TemplateTest.B' to 'TemplateTest.IChild<TemplateTest.ParentBase<TemplateTest.B>>'. Kbd2 C:\dev\Kbd2\TemplateTest.cs 16 Active
Error CS0311 The type 'TemplateTest.C' cannot be used as type parameter 'TChild' in the generic type or method 'ParentBase<TChild>'. There is no implicit reference conversion from 'TemplateTest.C' to 'TemplateTest.IChild<TemplateTest.ParentBase<TemplateTest.C>>'. Kbd2 C:\dev\Kbd2\TemplateTest.cs 20 Active
Error CS1721 Class 'B' cannot have multiple base classes: 'ParentBase<C>' and 'IChild<A>' Kbd2 C:\dev\Kbd2\TemplateTest.cs 20 Active
Error CS0311 The type 'TemplateTest.B' cannot be used as type parameter 'TParent' in the generic type or method 'IChild<TParent>'. There is no implicit reference conversion from 'TemplateTest.B' to 'TemplateTest.ParentBase<TemplateTest.IChild<TemplateTest.B>>'. Kbd2 C:\dev\Kbd2\TemplateTest.cs 24 Active
我甚至不确定这是否可以编译,因为类相互依赖。难道我做错了什么 ?谢谢。
编辑 :添加了未实现的方法和更新的错误列表。
编辑 :通过使子接口成为基类而不是接口来简化示例,就像父类一样。
编辑 :实际上只允许一个基类,所以我将子类型转换回接口而不是类。
编辑 :如果我删除其中任何一个&#34;其中&#34;约束,错误都消失了。是因为他们互相依赖吗?
答案 0 :(得分:0)
您当前的方法存在的问题是它依赖于某种奇怪的递归。这就像说:
如果您再考虑一下,父/子关系涉及两种类型:
public interface IChild<P, C> where P : IParent<P, C> where C : IChild<P, C> {
P Parent { get; set; }
}
public interface IParent<P, C> where P : IParent<P, C> where C : IChild<P, C> {
IList<C> Children { get; }
}
虽然这可能有效但看起来非常复杂,因为在IParent
中未使用类型参数P
,而在IChild
中未使用类型参数C
。
但我认为我们正走在正确的轨道上。如果您简化接口并将通用约束添加到ParentBase
,您将获得更易理解的内容:
public interface IChild<P> {
P Parent { get; set; }
}
public interface IParent<C> {
IList<C> Children { get; }
}
public class ParentBase<P, C> : IParent<C> where C : IChild<P> {
public IList<C> Children { get; } = new List<C>();
}
使用此设计,您有separated concerns:
您的示例有效:
public class A : ParentBase<A, B> {
}
public class B : ParentBase<B, C>, IChild<A> {
public A Parent { get; set; }
}
public class C : IChild<B> {
public B Parent { get; set; }
}
public class Demo {
public static void Test() {
var a = new A();
var b = new B() { Parent = a };
var c = new C() { Parent = b };
a.Children.Add(b);
b.Children.Add(c);
System.Console.WriteLine(c.Parent.Parent == a);
}
}
还有一些其他细节需要注意:
IList<T>
从实现中抽象出来children
中的ParentBase
)并不常见,大多数人使用只读属性来封装列表本身