从具有继承接口的父级实现继承接口
本文关键字:继承 接口 实现 | 更新日期: 2023-09-27 18:31:19
假设我有以下 3 个接口(格式是为了简洁起见而设计的):
public interface ISecondary { }
public interface ITertiary { }
public interface IRoot
{
public ISecondary secondary
public ITertiary tertiary
}
我有继承各自接口的二级和三级类(为了简洁起见,格式化):
public class Secondary : ISecondary { }
public class Secondary2 : ISecondary { }
public class Tertiary : ITertiary { }
public class Tertiary2 : ITertiary { }
我希望能够将嵌入的类嵌入到包含两个接口的根类中,如下所示:
public class Root : IRoot
{
public Secondary secondary { get; set; }
public Tertiary tertiary { get; set; }
public string foo { get; set; } // This wouldn't need to be cross-compatible
}
public class Root2 : IRoot
{
public Secondary2 secondary { get; set; }
public Tertiary2 tertiary { get; set; }
public double bar { get; set; } // This wouldn't need to be cross-compatible either
}
然后我想做一些类似的事情(对不起,反思不是我的强项):
Root root = new Root();
// data is entered
Root2 root2 = new Root(IRoot root)
// Similar to how ObservableCollection can retrieve data
// from a List of the same generic type. This constructor
// would take data from the IRoot properties and put it into root2.
以便 IRoot 的所有成员都从根转移到根 2。
在 C# 中执行此操作将导致匹配类型错误 (CS0738)。
换句话说(如果这很难理解,我深表歉意)我希望我的根接口在我的 IRoot 接口将具有的 HAS-A 关系中使用来自二级和三级接口的签名,但在实现根类时,我也想实现它们各自的继承类,而不必使用实际接口。
谢谢你的时间。
由于
Root
实现IRoot
并且IRoot
需要接口类型的属性,因此必须在Root
中将这些属性声明为接口。
public class Root : IRoot
{
public ISecondary secondary { get; set; }
public ITertiary tertiary { get; set; }
}
这仍然允许您为它们分配类
IRoot root = new Root {
secondary = new Secondary(),
tertiary = new Tertiary()
};
如果出于某种原因,您想要访问不属于ISecondary
接口的 Secondary
对象的成员,则可以这样做:
var secondary = root.secondary as Secondary;
if (secondary != null) {
secondary.DoSomething();
}
另一种方法是使用泛型和泛型类型约束
public interface IRoot<TSecondary, TTeritary>
where TSecondary : ISecondary
where TTeritary : ITertiary
{
public TSecondary secondary
public TTeritary tertiary
}
然后你可以像这样声明两个根类
public class Root : IRoot<Secondary, Tertiary>
{
public Secondary secondary { get; set; }
public Tertiary tertiary { get; set; }
}
public class Root2 : IRoot<Secondary2, Tertiary2>
{
public Secondary2 secondary { get; set; }
public Tertiary2 tertiary { get; set; }
}
但是,请注意,这两个类不兼容赋值。优点只是强制执行由接口定义的特定结构。如果您确实需要赋值兼容性,请删除 setter 并使用 out
修饰符:
public interface IRoot<out TSecondary, out TTeritary>
where TSecondary : ISecondary
where TTeritary : ITertiary
{
TSecondary secondary { get; }
TTeritary tertiary { get; }
}
现在你可以这样做了
var list = new List<IRoot<ISecondary, ITertiary>>();
list.Add(new Root());
list.Add(new Root2());
好吧,要实现接口,您必须使用相同的类型,但您可以保留更具体的实现并显式实现接口属性:
public class Root : IRoot
{
public Secondary secondary { get; set; }
public Tertiary tertiary { get; set; }
public string foo { get; set; } // This wouldn't need to be cross-compatible
ISecondary IRoot.secondary {get {return this.secondary;} set{;}}
ITertiary IRoot.tertiary {get {return this.tertiary;} set{;}}
}
这样,您就可以以类型安全的方式使用更独特的类型,而无需强制转换。 然而,问题在于secondary
和tertiary
的二传手。 因为你可以传入任何ISecondary
,所以不能保证传入的对象是Secondary
,所以你不能安全地将它分配给secondary
属性。 您的选择是:
- 强制转换为
Secondary
,如果不是该类型,则会引发异常 - 确定是否可以投射到
Secondary
,如果不能,请执行其他操作 - 将属性设为
IRoot
仅获取