0

我有一个通用接口层次结构,它描述了其他通用类型的一些控制器,我很难在脑海中澄清为什么特定的强制转换场景无效。

简化代码如下;

// 'DTO' interfaces
public interface IBase
{ }

public interface IDerived : IBase
{ }


// 'DTOs'
public class Base : IBase
{ }

public class Derived : Base, IDerived
{ }


// controller interfaces
public interface IBaseController<T> where T : class, IBase
{ }

public interface IDerivedController : IBaseController<IDerived>
{ }


// controllers
public class BaseController<T> : IBaseController<T>
    where T : class, IBase
{ }

public class DerivedController : BaseController<IDerived>, IDerivedController
{ }

现在,我遇到的问题是这样的;

IDerivedController x = new DerivedController();
bool is1 = x is IDerivedController;   // true
bool is2 = x is IBaseController<IDerived>; // true
bool is3 = x is IBaseController<IBase>; // false ???

最后一行是我的困惑所在。控制器接口与“DTO”正确关联。但不是两者都在一起......?

4

3 回答 3

1

想一想,如果你有一组形状,这意味着什么: is aCollection<Triagle>与 ( is-a )相同Collection<Shape>吗?如果是这样的话,我们可以将任何形状放入我们的三角形集合中。OTOH 如果Collection<Shape>是 ( is-a ) Collection<Triangle>,那么我们可以把 aSquare放在那里(毕竟,它是一个形状的集合),并期望只得到Triangles 。

对你来说也是如此BaseController<Iderived>

于 2012-05-22T00:23:21.320 回答
1

有关变体通用接口的信息,请参阅http://msdn.microsoft.com/en-us/library/dd997386,这是您所问问题的核心。您必须声明 anIBaseController<IDerived>实际上可以用作 anIBaseController<IBase>以便它可以这样使用。

出于这个原因,请考虑尝试使用 a List<string>as anIList<object>与尝试使用 an IEnumerable<string>as an IEnumerable<object>。转换没问题,因为您可以毫无问题IEnumerable地将项目用作s,但不能将任何项目添加到 a ,因为它会包含除s 之外的其他内容。objectobjectList<string>string

如果将其更改为public interface IBaseController<out T> where T : class, IBase,则x is IBaseController<IBase>变为true。如果编译器抱怨你不能做T一个out参数,那么你就不能做你想做的转换(除非你改变接口以使其兼容)。

于 2012-05-22T00:26:08.017 回答
1

这是因为IBaseController不是协变的。您可以通过像这样声明它来使其成为协变的:

public interface IBaseController<out T> where T : class, IBase
{
}

但那时T只能用于输出位置。

想象一下你的界面是这样的:

public interface IBaseController<T> where T : class, IBase
{
    void DoSomething(T x);
}

IBaseController<IDerived>中,方法签名将是:

void Something(IDerived x)

现在,如果IBaseController<IDerived>可以分配给IBaseController<IBase>,您可以执行以下操作:

public class Derived2 : Base
{ }


IDerivedController x = ...
IBaseController<IBase> y = x;
y.DoSomething(new Derived2()); // oops! Derived2 doesn't implement IDerived
于 2012-05-22T00:27:33.690 回答