4

ラップされたオブジェクトのいずれかを使用できる場所ならどこでも使用できるようにしたい複合オブジェクトを作成しています。したがって、次のオブジェクトが与えられます。

public class Foo{}

public class FooWrapper{
    private Foo _foo = new Foo();

    public static implicit operator Foo(FooWrapper wrapper)
    {
       return wrapper._foo;
    }
}

次のテストをパスさせたい:

public class ConversionTests
{
     private FooWrapper _uat = new FooWrapper();

     [Test]
     public void Can_Use_Is_Operator()
     {
          Assert.IsTrue(_uat is Foo);
     }

     [Test]
     public void Can_Use_As_Operator()
     {
          Assert.IsTrue(null != _uat as Foo);
     }
}

MSDN のドキュメントを確認しました
: http://msdn.microsoft.com/en-us/library/scekt9xw.aspx
as: http://msdn.microsoft.com/en-us/library/ cscsdfbt%28v=vs.110%29.aspx

ドキュメントは、それが不可能であることを意味します。

is 演算子は、参照変換、ボックス化変換、ボックス化解除変換のみを考慮することに注意してください。ユーザー定義の変換など、その他の変換は考慮されません。

FooWrapper を構築する方法があるかどうかを知っている人はいますか? おそらくIConvertibleのようなインターフェースを実装していますか?

おまけの質問: as/is がユーザー定義の変換を考慮しない理由を知っている人はいますか?

(そして、この質問が重複していたら申し訳ありません。'as' と 'is' は、stackoverflow では (ほとんどの検索エンジンと同様に) ストップ ワードのように見えるため、これらのキーワードを含む質問を検索することは非常に困難です。)

4

3 に答える 3

8

ドキュメントは、それが不可能であることを意味します

ドキュメントは正しいです。

FooWrapper を構築する方法があるかどうかを知っている人はいますか?

知っている。存在しない。(明らかに、FooWrapperの派生クラスを作成することは別としてFoo。)

isand演算子は、オブジェクトが実際asに何であるかを示すためにあります。嘘をつくようにしないでください。

おそらくIConvertibleのようなインターフェースを実装していますか?

いいえ。

as/is がユーザー定義の変換を考慮しない理由を知っている人はいますか?

まず、先ほど言ったように、 の目的はオブジェクトが実際isに何であるかを伝えることです。

第 2 に、議論のために、C# コンパイラ チームが、ユーザー定義の変換を使用 する演算子frobのセマンティクスを持つ新しい演算子 (たとえば、 ) を追加したいと考えているためです。がである場合を返します。その式に対して生成されるのを確認したい IL を説明してください。この演習に取り組むことで、なぜそれが難しい問題なのかがわかると思います。asx frob FooFooxFooWrapper

于 2013-08-22T21:14:47.547 に答える
2

FooWrapperが と見なされるためにFooは、FooWrapperから継承する必要がありFooます。あれは:

class FooWrapper: Foo
{
}

ただし、問題は、ラッパーでオブジェクトもラップしたい場合Bar、それができないことです。C# は多重継承をサポートしていないためです。

通常、複数のオブジェクトのように動作するラッパーが必要な場合は、インターフェイスを実装します。たとえば、次のようになります。

public interface IFoo
{
}

public class Foo: IFoo  // implements the IFoo interface
{
}

public interface IBar
{
}

public class Bar: IBar
{
}

public class MyWrapper: IFoo, IBar  // Implements the IFoo and IBar interfaces
{
    private IFoo _theFoo;
    private IBar _theBar;
    public MyWrapper(IFoo foo, IBar bar)
    {
        _theFoo = foo;
        _theBar = bar;
    }
}

そしてもちろん、とMyWrapperのすべてのメソッドを実装し、呼び出しを適切な含まれるオブジェクトに渡す必要があります。したがって、メソッドを宣言した場合、(クラス内で) 次のようになります。IFooIBarIFooFrobMyWrapper

    public void Frob()
    {
        _theFoo.Frob();
    }

それが暗黙のインターフェースの実装です。また、インターフェイス メソッドの明示的な実装を調べる必要がある場合もあります。

ラッパーを作成するには:

MyWrapper wrapper = new MyWrapper(new Foo(), new Bar());

したがって、テストでは、具体的なクラスではなくインターフェイスをチェックするためにisandを使用します。as

var isFoo = wrapper is IFoo;
IFoo myFoo = wrapper as IFoo;
于 2013-08-22T21:13:19.760 に答える
1

is/がラッパー クラスで動作する唯一のオプションasは、ラッピング クラスが実際にラップされたクラスである場合です。ラップしたいクラスが封印されていない場合は、そこから派生できます...

実際に達成しようとしていることは、一般的なケースでは不可能です - .Net/C# はどのメソッドが呼び出されるかを静的に検出し、ラップされたオブジェクトのすべての非仮想メソッドは、そのタイプ (または派生したもの) のオブジェクトで直接呼び出す必要があります。 、ただし、それらをオーバーライドすることはできません。静的メソッドはさらに困難です。

var item = new InnerType();
// you can't create any class that will replace method in this call
item.NonVirtual();

// No way to replace static method with wrapper
var result = InnerType.StaticMethod();

// At least virtual methods can be overriden if Wrapper derives from InnerType
item.VirtualMethod();

コードでインターフェイスを使用してオブジェクトと対話する場合、インターフェイスを別の実装に置き換えることが完全にサポートされているため、タスクがはるかに簡単になります。手動ラッパーまたはリフレクション/エミットを介して自動的に作成されたもののいずれかが機能します。

var itemByInterface = (IInnerType)Factory.CreateInnerType();
itemByInterface.InterfaceMethod();

// is/as checks should use interface
var isRightType = itemByInterface is IInnerType;

// do not use static/non-interface calls 

is/as が他の変換を考慮しない理由についての私の考え:

  • 操作の期待は非常に迅速で軽量なチェックです - 他の変換はオブジェクトを作成する必要があるかもしれません/それにかかる時間は予測できません。
  • コンパイラが考慮できるオプションの数が大幅に増えるため、速度が低下します
  • オブジェクトが使用される他の多くの場合、変換は考慮されないため、isレポートは成功するがオブジェクトが正しく使用されない (インスタンスがリストに追加されるなど) という一貫性のないコード動作につながる可能性があります。
于 2013-08-22T21:12:04.410 に答える