3

次のシナリオを検討してください。

を返すメソッドがありますが、またはのISomething可能性があります。したがって、結果をキャストして使用しますが、失敗します。理由または解決方法についての助けをいただければ幸いです。SomethingWrapped<Something>Something

class Program
{
    static void Main(string[] args)
    {
        var a = new DerivedSomething();
        var b = (DerivedSomething)new Wrapped<DerivedSomething>(a); //success
        var c = (DerivedSomething)_GetSomething(false); //success, obsiously!
        var d = (DerivedSomething)_GetSomething(true); //Unable to cast object of type 'test_bed.Wrapped`1[test_bed.DerivedSomething]' to type 'test_bed.DerivedSomething'.
        var e = (DerivedSomething)(ISomething)new Wrapped<DerivedSomething>(a);  //Unable to cast object of type 'test_bed.Wrapped`1[test_bed.DerivedSomething]' to type 'test_bed.DerivedSomething'.

        var works = ((DerivedSomething)_GetSomething(false)).DoSomethingElse(); 
        var fails = ((DerivedSomething)_GetSomething(true)).DoSomethingElse(); //cast exception
    }

    private static ISomething _GetSomething(bool wrap)
    {
        var something = new DerivedSomething();
        return wrap ? new Wrapped<DerivedSomething>(something) : (ISomething)something;
    }
}

public interface ISomething
{
    void DoSomething();
}

public abstract class Something : ISomething
{
    public void DoSomething()
    {
        //some code
    }
}

public class DerivedSomething : Something
{
    public void DoSomething()
    {
        //some code
    }

    public void DoSomethingElse()
    {
        //some code
    }
}

public class Wrapped<T> : ISomething
    where T : ISomething
{
    private readonly T _something;

    public Wrapped(T something)
    {
        _something = something;
    }

    public void DoSomething()
    {
        _something.DoSomething();
    }

    public static explicit operator T(Wrapped<T> wrapped)
    {
        return wrapped._something;
    }
}

キャストしようとしたときに型がインターフェイスとして公開されている場合、演算子が見つからないように見えますか?

Wrapped<Something>「簡単な」解決策は、オプションでtoをアンラップする「アンラップ」関数を作成することですSomethingが、可能であれば演算子を使用することをお勧めします。

編集

問題の核心は次のとおりだと思います。返品される_GetSomething()かどうSomethingかはわかりません。Wrapped<Something>

4

3 に答える 3

4

明示的な変換はコンパイル時にバインドされます (追加のヒントは、変換演算子が静的であることです)。

試す

var f = (Something)(Wrapped<Something>)_GetSomething(true);

これは成功します

あなたの場合、コンパイラはあなたの型がであることを知っているだけで、それがたまたますでにある場合を除いて、をaISomethingに変換する方法を知りません。ISomethingSomethingSomething

あなたの例に変更public class Wrapped<T> : ISomethingすることpublic class Wrapped<T> : Somethingで正常に実行されますが、Wrapped<T>すでにT.

注:
これexplicit operatorはキャストではなく、型変換であり、呼び出されたメソッドであり、そのメソッドはコンパイル時の型に基づいて解決されます(あなたの場合はISomething)。型変換が型キャストと同じ構文を持つことは、混乱の元です。キャストは、既存のオブジェクトを互換性のある型の別の変数に割り当てるだけですが、型変換は実際には新しいオブジェクトを返します。

于 2012-04-13T07:19:18.857 に答える
2

キャスト演算子は次のようになります。

public static explicit operator T(Wrapped<T> wrapped)
{
        return wrapped._something;
}

そして、あなたは次のようにキャストしています

var d = (Something)_GetSomething(true); //FAILS!

にキャストすることはできません。Something原因Somethingは、の具体的な実装ですT:ISomething。この作品を作るには、次のように書く必要があります。

var d = (ISomething)_GetSomething(true); //SUCCESS!

また

本当に具象型を使用したい場合は、次のようなジェネリックを定義できます。

public class Wrapped<T> : Something //Something and NOT ISomething 
    where T : ISomething
{
    .....
    .....
}
于 2012-04-13T07:18:05.457 に答える
0
var d = (Something)(Wrapped<Something>)_GetSomething(true); 
var e = (Something)new Wrapped<Something>(a);
于 2012-04-13T07:24:01.207 に答える