web-dev-qa-db-ja.com

インターフェイスに制限されているジェネリック型パラメーターで「as」を使用できないのはなぜですか?

以下の例(デモ目的のみ)では、Tがクラスに制約されていない場合、この変換は次のようになります。

var ret = objectA as T;

..次のコンパイルエラーが発生します:

型パラメーター「T」は、クラス型制約も「クラス」制約もないため、「as」演算子と一緒に使用することはできません。

なぜこれができないのか理解できません。 TをインターフェイスIObjectに制約したので、コンパイラはTがインターフェイスタイプであり、as操作が有効であることを認識している必要があります。

public interface IObject
{
    string Id { get; set; }
}
public class ObjectA : IObject
{
    public string Id { get; set; }
}
public class ObjectFactory
{
    public T CreateObject<T>(string id) where T : IObject
    {
        ObjectA objectA = new ObjectA();
        var x = objectA as IObject; // this is good
        var ret = objectA as T; // why this 'as' cannot compile?
        return ret;
    }
    public T CreateClassObject<T>(string id) where T : class, IObject
    {
        ObjectA objectA = new ObjectA();
        var ret = objectA as T; // if T is class, this 'as' can compile
        return ret;
    }
}
22
ricky

tをインターフェイスIObjectに制限したので、コンパイラはTがインターフェイスタイプである必要があり、「as」操作が有効である必要があることを認識している必要があります。

いいえ、Tはインターフェースタイプである必要はありません。 インターフェースを実装するタイプである必要があります。考えてみましょう:

_public struct Foo : IObject
{
    public string Id { get; set; }
}
_

では、CreateObject<Foo>("ff")に何を期待しますか?

classCreateObject制約がある場合、Fooは参照型ではないため、その呼び出しは無効になります-コンパイラはTが参照型なので、_objectA as T_は問題ありません。

35
Jon Skeet