9

我收到以下错误:

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
}

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

4

2 回答 2

8

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

  1. 使您的界面通用
  2. 显式实现接口。

如果你做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 永远不会在您的代码中以错误的类型被调用,那么这可能会起作用。

于 2011-02-03T17:13:49.813 回答
6

你是对的,这与协方差有关;具体来说,它与虚方法返回类型协方差有关,这不是 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.

即使协方差完全合法,这种协方差也不合法;您必须没有设置器才能使协方差合法。

假设你没有二传手:

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。

于 2011-02-03T18:03:31.170 回答