4

2つの制限を考慮してください-

  1. MyPropertyをインターフェイスまたは抽象クラスに移動できません。
  2. FooEventHandlerはドットネットフレームワークメソッドであるため、パラメーターの種類を変更することはできません。

MyPropertyをいくつかのクラスで定義しています。

class A
    {
        public string MyProperty { get; set; }
    }
    class B
    {
        public string MyProperty { get; set; }
    }
    class C
    {
        public string MyProperty { get; set; }
    }

メソッドFooEventHandlerは、受け取ったすべてのパラメーターについてこのプロパティを更新します。

public object FooEventHandler(object obj)
    {
        object toReturn = null;
        if (obj.GetType() == typeof(A))
        {
            (obj as A).MyProperty = "updated";
            toReturn = obj;
        }
        else if (obj.GetType() == typeof(B))
        {
            (obj as B).MyProperty = "updated";
            toReturn = obj;
        }
        else if (obj.GetType() == typeof(C))
        {
            (obj as C).MyProperty = "updated";
            toReturn = obj;
        }
        return toReturn;
    }

そして、FooEventHandlerはこのように繰り返し呼び出されます-

static void Main(string[] args)
    {
        Program program = new Program();
        A objA = new A();
        program.FooEventHandler(objA);
        B objB = new B();
        program.FooEventHandler(objB);
        C objC = new C();
        program.FooEventHandler(objC);
    }

一般に上記の2つの制限を考慮して、Fooで冗長なコードを削除する方法を提案してください。

より正確には、WCFでParameterInspectorを使用しているときにこの問題が発生しました。ここでインターセプトされたすべてのリクエストを適切に変更しようとしていますが、operationNameに基づいてSwitchCaseを作成する必要がありました。

上記のA、B、C、Dクラスはプロキシです。したがって、そもそもそれらを変更したくありません。サービスリファレンスを更新すると、iterfaceの変更が上書きされます。

public object BeforeCall(string operationName, object[] inputs){
    // update inputs[0] properties
    }

ご協力ありがとうございました。

4

5 に答える 5

10

実際にクラスにインターフェースを実装させて、これを操作しやすくすることができます。重要なのは、生成されたサービス参照クラスがpartialであるということです。つまり、コードが再生成されたときに上書きされない別のファイルでこれを行うことができます。

namespace ServiceReferenceNamespace {
 public partial class A : IMyProperty { }
 public partial class B : IMyProperty { }
 public partial class C : IMyProperty { }
}

どこIMyPropertyにありますか:

public interface IMyProperty { string MyProperty { get; set; } }

次に、FooEventHandlerメソッドを変更して、を取得するIMyPropertyか、を取得しobjectてチェックしobj is IMyPropertyます(または、を使用asして、チェックが1回だけ実行されるようにします)。これにより、リフレクションや動的な複雑さ、およびこれらのアプローチによる実行時のパフォーマンスへの影響なしに、プロパティを簡単に使用できます。

于 2012-10-04T19:06:36.853 に答える
5

あなたが利用可能であると仮定dynamicします:

dynamic toReturn = obj;
toReturn.MyProperty = "updated";
return toReturn;

MyPropertyに存在しない場合、これはスローされobjます。

テスト済み:

[Test]
public void X()
{
    A objA = new A();
    var x = FooEventHandler(objA);
    Assert.IsInstanceOf<A>(x);
    Assert.AreEqual("updated", (x as A).MyProperty);

    B objB = new B();
    var y = FooEventHandler(objB);
    Assert.IsInstanceOf<B>(y);
    Assert.AreEqual("updated", (y as B).MyProperty);

    C objC = new C();
    var z = FooEventHandler(objC);
    Assert.IsInstanceOf<C>(z);
    Assert.AreEqual("updated", (z as C).MyProperty);

    D objD = new D();
    Assert.Throws<RuntimeBinderException>(() => FooEventHandler(objD));
}

class D {}
于 2012-10-04T19:00:12.533 に答える
3

私の最初の考えは、イベントハンドラーでリフレクションを使用することです。

public object FooEventHandler(object obj)
{
    obj.GetType().GetProperty("MyProperty").SetValue(obj, "updated", null);
    return obj;
}
于 2012-10-04T19:03:08.140 に答える
3

リフレクションを使用して、これらの条件を確認してから、次の値を設定できます。

  1. 期待される特性を持っていますMyProperty
  2. MyPropertyタイプですstring
  3. MyPropertyセッターがあります

public object FooEventHandler(object obj)
{
  if (obj == null)
    return null;

  var property = obj.GetType().GetProperty("MyProperty");
  if (property != null && property.PropertyType == typeof(string) && property.GetSetMethod(true) != null)
  {
    property.SetValue(obj, "updated", new object[]{ });
    return obj;
  }

  return null;
}
于 2012-10-04T19:05:00.503 に答える
1

編集
ティムSの答えはおそらく最も簡単で安全です。ただし、部分クラスはすべて同じアセンブリに含まれている必要があります。何らかの理由でプロキシクラスを含むアセンブリを編集できない場合でも、これを行うことができます。

元の回答

これは少し過剰かもしれません。

新しいインターフェースを作成する

public interface IProxyWrapper
{
    string MyProperty { get; set; }
}

AWrapper/BWrapperとを実装しCWrapperます。これを行うには2つの異なる方法があります。A残りはそこから簡単なはずなので、ここでのみ示します。

public class AWrapper : IProxyWrapper
{
    public string MyProperty { get; set; }
}

または

public class AWrapper : A, IProxyWrapper
{
    string IProxyWrapper.MyProperty 
    { 
        get { return base.MyProperty; }
        set { base.MyProperty = value; }
    }
}

2番目の利点は、を使用できるAWrapper場所ならどこでも使用できることですA

いずれにせよ、ラッパーからProxyクラスに値を取得する方法を見つける必要があります。AutoMapperのようなものを使用してプロパティを設定するか、コンストラクターパラメーターとして渡し、フィールドに格納して、IProxyWrapper.MyPropertywrapに実装することができますA.MyProperty

値をプロキシに戻すことに関しては、AutoMapperが再びあります。または、何らかの方法でフィールドを公開できます。

プロキシを再生成するときに失われることを心配せずに、アプリケーション用にこれらのラッパークラスをさらにカスタマイズできるようになりました。

于 2012-10-04T19:11:27.007 に答える