假设我有以下类层次结构:
class A { }
class B : A { }
class C : A { }
我有两个容器类:
class BContainer { public B[] value { get; set; } }
class CContainer { public C[] value { get; set; } }
我需要定义一个方法,该方法可以接受两个类实例中的任何一个,并且可以访问value
属性而无需求助于反射。有没有办法可以定义两个类都可以实现的接口(比如IContainer
)?如果是这样,接口中value
属性的类型是什么?
使用示例:
void ProcessValue(IEnumerable<A> as) { ... }
void ExtractValue(IContainer container)
{
ProcessValue(container.value);
}
答案 0 :(得分:3)
您可以将界面定义为:
interface IContainer<T>
where T : A
{
T[] Value { get; set; }
}
那么你的课程将是:
class BContainer : IContainer<B> { public B[] Value { get; set; } }
class CContainer : IContainer<C> { public C[] Value { get; set; } }
然后处理方法也应该是通用的:
void ExtractValue<T>(IContainer<T> container)
where T : A
{
ProcessValue(container.Value);
}
答案 1 :(得分:3)
由于属性的类型在两个类中不同,因此类型应该是两个属性的通用类型。在这种情况下IEnumerable<A>
应该没问题。问题是您定义的两个属性不能是此接口的实现,您可以使用显式接口实现来定义一个单独的属性,其名称与服务器相同,作为接口属性的实现。
class A { }
class B : A { }
class C : A { }
interface IContainer
{
IEnumerable<A> value { get; }
}
class BContainer : IContainer
{
public B[] value { get; set; }
IEnumerable<A> IContainer.value => this.value;
}
class CContainer : IContainer
{
public C[] value { get; set; }
IEnumerable<A> IContainer.value => this.value;
}
用于显式实现的属性将从外部和类内部隐藏。如果您访问this.value
,则表示您正在访问类的值版本,除非将引用明确强制转换为IContainer
(ex ((IContainer)this).value
这将访问该属性的接口版本)
答案 2 :(得分:2)
似乎是泛型的好例子:
class Container<T> where T : A
{
public T[] value { get; set; }
}
答案 3 :(得分:1)
你可以这样做:
public class A { }
public class B : A { }
public class C : A { }
public interface IContainer
{
A[] value { get; }
}
class BContainer : IContainer { public B[] value { get; set; } A[] IContainer.value { get { return this.value; } } }
class CContainer : IContainer { public C[] value { get; set; } A[] IContainer.value { get { return this.value; } } }
void ProcessValue(IEnumerable<A> arg) { }
void ExtractValue(IContainer container)
{
ProcessValue(container.value);
}
这至少可以编译。
答案 4 :(得分:1)
如果您想要一个非通用IContainer
,您可以将这两个集合视为相同,那么那里并不是一个非常干净的选项,因为类型是不同的。方差讨厌类型差异。您可以使用 generics ,但这对您有所帮助,因为您需要单独检查每个已关闭的通用类型,就像您当前需要检查{{1}一样和B
分开。
在非通用API上最接近 的将在C
中返回Array
或IList
(非通用),这是太可怕了,并没有让你前进很多。
或者,如果您只需枚举项目,则可以使用泛型的方差功能将项目作为基本类型:
IContainer
class BContainer : IContainer
{
public B[] value { get; set; }
IEnumerable<A> IContainer.Value => value;
}
class CContainer : IContainer
{
public C[] value { get; set; }
IEnumerable<A> IContainer.Value => value;
}
interface IContainer
{
IEnumerable<A> Value { get; }
}
和BContainer
都可以视为CContainer
,给定IContainer
您可以将项目重复为IContainer
s < / em>的
答案 5 :(得分:0)
我不确定这些通用答案是否适用于您的序列化要求。
一些重载怎么办?
void ExtractValue(BContainer container)
{
ProcessValue(container.Value);
}
void ExtractValue(CContainer container)
{
ProcessValue(container.Value);
}