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

See http://msdn.microsoft.com/en-us/library/dd997386 for info on variant generic interfaces, which is the heart of what you're asking. You must declare that an IBaseController<IDerived> can in fact be used as an IBaseController<IBase> in order for it to be used as such.

For the reason for this, consider trying to use a List<string> as an IList<object> vs trying to use an IEnumerable<string> as an IEnumerable<object>. The IEnumerable conversion is ok because you can use the items as objects without any problems, but you can't add any object to a List<string>, because then it would contain something besides strings.

If you change it to public interface IBaseController<out T> where T : class, IBase, then x is IBaseController<IBase> becomes true. If the compiler complains that you can't make T an out parameter, then you can't do the conversion you're looking to do (unless you change the interface to make it compatible).

于 2012-05-22T00:26:08.017 に答える
1

This is because IBaseController is not covariant. You could make it covariant by declaring it like this:

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

But then T could only be used in an output position.

Imagine your interface looks like this:

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

In IBaseController<IDerived>, the method signature would be:

void Something(IDerived x)

Now, if IBaseController<IDerived> were assignable to IBaseController<IBase>, you could do something like this:

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 に答える
1

図形のコレクションがある場合、それはどういう意味になるか考えてみてください: aは ( is-a )Collection<Triagle>と同じですか? それが可能であれば、三角形のコレクションに任意の形状を入れることができます。OTOHが ( is-a )である場合、そこに a を入れることができ(結局のところ、これは形状のコレクションです)、s のみを取得することを期待できます。Collection<Shape>Collection<Shape>Collection<Triangle>SquareTriangle

同様のことがあなたにも当てはまりますBaseController<Iderived>

于 2012-05-22T00:23:21.320 に答える