我可以为具有相同属性名称的两个类定义公共接口吗?

时间:2017-12-08 10:55:59

标签: c#

假设我有以下类层次结构:

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);
}

6 个答案:

答案 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中返回ArrayIList(非通用),这是太可怕了,并没有让你前进很多。

或者,如果您只需枚举项目,则可以使用泛型的方差功能将项目作为基本类型:

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);
}