7

私はこのテストに合格したいのですが、誰かがそれを行う方法を知っていますか?

public class Something
{
    public string Name {get; set}
}

public interface IWithId
{
    public Guid Id {get; set}
}

public class IdExtender 
{
    public static Object Extend(object toExtend)
    {
        ...?
    }
}

public class Tests 
{
    [Test]
    public void Should_extend_any_object()
    {
        var thing = new Something { Name = "Hello World!"};
        var extended = IdExtender.Extend(thing);
        Assert.IsTrue(extended is IWithId);
        Assert.IsTrue(extended.Id is Guid);
        Assert.IsTrue(extened.Name == "Hello World!");
    }
}

このようなことは、城の動的プロキシ、linfuなどで実行できると思います...しかし、どのように?

4

5 に答える 5

3

今のところ私はこのようなlinfuで行きます:

public class IdExtender 
{
    public static Object Extend(object toExtend)
    {
        var dyn = new DynamicObject(toExtend);
        dyn.MixWith(new WithId {
                                Id = Guid.New()
                               });
        var extended = dyn.CreateDuck<IWithId>(returnValue.GetType().GetInterfaces());
        return extended;
    }
}
于 2010-08-16T23:15:57.383 に答える
3

キャッスルDPの使用(明らかに)

プログラムの実行中に既存の型に新しいインターフェイスを取得させることはできないため、返す新しいオブジェクトを作成する必要があります。

これを行うには、プロキシを作成してから、既存のオブジェクトの状態をプロキシに複製する必要があります。DPはそのOOTBを行いません。v2.5では、ターゲットで新しいクラスプロキシを使用できましたが、これは、タイプのすべてのプロパティが仮想である場合にのみ機能します。

ともかく。IWithIdプロパティを実装する既存のオブジェクトとプロキシを混在させることにより、新しいタイプにインターフェイスを取得させることができます。次に、インターフェイスのメンバーへの呼び出しがオブジェクトに転送されます。

または、実装するための追加のインターフェイスとして提供し、インターセプターに実装者の役割を任せることもできます。

于 2010-08-17T06:59:16.977 に答える
1

MoqやRhinoMocksのようなモックフレームワークを使用してみませんか。プロキシを直接作成する手間をかけずに、インターフェイスを動的に実装できます。

Moqを使用すると、次のように書くことができます。

var mock = new Mock<IWithId>();  // mock the interface
mock.Setup(foo => foo.Name).Returns("Hello World"); // setup a property

それとは別に、あなたはあなたが望むものを得るためにいくつかの複雑な仕事をしなければならないでしょう。私の知る限り、実行時に既存のクラスにメソッドやプロパティを追加することはできません。渡された型から動的に継承する新しいオブジェクトのインスタンスを返すことができます。Castleは間違いなくこれを許可しますが、必要なコードは特にエレガントでも単純でもありません。

于 2010-08-16T21:06:56.803 に答える
1

プロパティまたはインターフェイスを動的にアタッチする方法の問題は別として、あなたがやろうとしていることは、既存のクラスを追加のデータで拡張することのように思えます。この問題の非常に一般的な解決策は、を使用しDictionary<Something, SomethingExtra>て、マッピングを維持するサービスクラスに格納することです。これで、SomethingExtraにアクセスする必要がある場合は、サービスクラスに関連情報を要求するだけです。

利点:

  1. 実装は、リフレクションと動的プロキシ生成を使用するソリューションよりも理解と保守が容易です。

  2. 拡張されている型から派生する必要がある場合、クラスを封印することはできません。情報を外部に関連付けることは、封印されたクラスでうまく機能します。

  3. 拡張オブジェクトの構築に責任を負うことなく、情報を関連付けることができます。どこにでも作成されたインスタンスを取得して、新しい情報を関連付けることができます。

短所:

  1. マッピングを維持するサービスインスタンスを注入する必要があります。これは、手動インジェクション(通常はコンストラクターを介して渡される)を使用している場合はIoCフレームワークを介して、他に選択肢がない場合はシングルトン静的アクセサーを介して行うことができます。

  2. 非常に多くのインスタンスがあり、それらが迅速に作成/削除されている場合、ディクショナリのオーバーヘッドが顕著になる可能性があります。プロキシの実装と比較して、オーバーヘッドが目立つようになる前に、非常に重い負荷が必要になると思います。

于 2010-08-16T21:42:41.770 に答える
1

私は先週、実際に同様の質問に答えました。私はまた、これを1つのことを行う小さなライブラリを作成しました。それは私が恥知らずに差し込んでいる私のブログから入手できます。

あなたが求めているのは、CastleDynamicProxyを使用してほぼ達成可能です。唯一の制約は、既存のインスタンスがインターフェースを実装する必要があり、関心のあるすべてのプロパティ/メソッドがそのインターフェースを介して利用できることです。

public static TIntf CreateMixinWithTarget<TIntf>(TIntf target, params object[] instances) where TIntf : class{

    ProxyGenerator generator = new ProxyGenerator();
    ProxyGenerationOptions options = new ProxyGenerationOptions();

    instances.ToList().ForEach(obj => options.AddMixinInstance(obj));

    return generator.CreateInterfaceProxyWithTarget <TIntf>(target, options);
}

[Test]
public void Should_extend_any_object()
{
    var thing = new Something { Name = "Hello World!"};
    var extended = CreateMixinWithTarget<ISomething>(thing, new WithId(), new GuidImpl());
    Assert.IsTrue(extended is IWithId);
    Assert.IsTrue(extended.Id is Guid);
    Assert.IsTrue(extened.Name == "Hello World!");
}
于 2010-08-17T00:43:12.333 に答える