我是否可以实现一个接口,该接口包含一个子类型属性的接口?

时间:2011-02-03 17:10:08

标签: c# interface covariance contravariance

我收到以下错误:

  

ClassName.PropertyName无法实现IClassType.PropertyName   因为它没有匹配的返回类型IBasePropertyType

现在,代码:

public class ClassName : IClassType
{
    public IChildPropertyType PropertyName { get; set; }
}

public interface IClassType
{
    public IBasePropertyType PropertyName { get; set; }
}

public interface IBasePropertyType
{
    // some methods
}

public interface IChildPropertyType : IBasePropertyType
{
    // some methods
}

有没有办法做我正在尝试的事情?我知道问题在于共同/逆转,但我似乎无法弄清楚如何做到这一点。

2 个答案:

答案 0 :(得分:8)

为了实现给定的接口,您必须具有相同的返回类型。但是,有一些潜在的解决方法可以让生活更轻松:

  1. 使您的界面通用
  2. 明确实现接口。
  3. 如果你IClassType是通用的,就像这样:

    public interface IClassType<T> where T : IBasePropertyType
    {
        public T PropertyName { get; set; }
    }
    

    ...然后您可以使用各种属性类型实现此接口:

    public class ClassName : IClassType<IChildPropertyType>
    {
        public IChildPropertyType PropertyName { get; set; }
    }
    

    另一种选择是让您的接口不是通用的,但是要有一个明确实现接口的通用基类型:

    public class ClassBase<T> : IClassType
        where T : IChildPropertyType
    {
        IBasePropertyType IClassType.PropertyName { 
            get {return PropertyName;}
            set {PropertyName = (IChildPropertyType)value;}
        }
        T PropertyName {get;set;}
    }
    

    请注意,最后一个选项并不理想,因为您必须动态地将属性强制转换为给定的子类型:虽然您可以保证每个IChildProperty类型都是IBasePropertyType,但您不能保证每个IBasePropertyType都是IChildPropertyType。但是,如果您可以从原始界面中删除setter,或者您可以采取其他步骤来保证在代码中永远不会使用错误的类型调用setter,那么这可能会有效。

答案 1 :(得分:5)

这是正确的,这与协方差有关;特别是它与虚方法返回类型协方差有关,这不是C#语言支持的一种协方差。

请注意,即使这样,您描述的系统也不是类型安全的。假设我们有:

interface IAnimal {}
interface IGiraffe : IAnimal {}
interface ITiger: IAnimal {}
class Tiger : ITiger {}
interface IHaveAnAnimal { IAnimal Animal { get; set; } }
class C : IHaveAnAnimal
{
    public IGiraffe Animal { get; set; }
}
...
IHaveAnAnimal x = new C();
x.Animal = new Tiger(); // Uh oh. We just put a Tiger into a property of type IGiraffe.

即使协方差完全合法,这种协方差也不合法;你必须有 no setter 才能使协方差成为合法的。

假设你确实没有setter:

interface IAnimal {}
interface IGiraffe : IAnimal {}
interface ITiger: IAnimal {}
class Tiger : ITiger {}
interface IHaveAnAnimal { IAnimal Animal { get; } }
class C : IHaveAnAnimal
{
    public IGiraffe Animal { get; }
}

不幸的是,这仍然不合法。但你可以这样做:

class C : IHaveAnAnimal
{
    IAnimal IHaveAnAnimal.Animal { get { return this.Animal; } }
    public IGiraffe Animal { get; }
}

现在当C用作C时,Animal返回一只长颈鹿,当使用IHaveAnAnimal时,它返回一个IAnimal。