4

请考虑两个限制 -

  1. 无法将 MyProperty 移动到接口或抽象类。
  2. FooEventHandler 是一个 dotnet 框架方法,因此不能更改参数类型。

我在几个类中定义了 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);
    }

请提出一种删除 Foo 中冗余代码的方法,考虑到上述两个限制。

更准确地说,我在 WCF 中使用 ParameterInspector 时遇到了这个问题。我正在尝试修改此处截获的所有请求的属性,并且必须根据 operationName 编写 Switch Case。

如上所述的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,所以检查只做一次)。这使您可以简单地使用该属性,而没有任何反射或动态复杂性以及这些方法对运行时性能的影响。

于 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

编辑
Tim S 的答案可能是最简单和最安全的。但是,部分类必须都在同一个程序集中。如果由于某种原因您无法编辑包含代理类的程序集,您仍然可以这样做。

原始答案

这可能有点过分了。

制作一个新界面

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

实施AWrapper/BWrapperCWrapper. 有两种不同的方法可以做到这一点。我只会展示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; }
    }
}

第二个的好处是您可以在AWrapper任何可以使用A.

无论哪种方式,您都需要找到一种将值从包装器获取到代理类的方法。您可以使用 AutoMapper 之类的东西来设置属性,或者将其作为构造函数参数传入,将其存储在字段中,然后实现IProxyWrapper.MyPropertywrap A.MyProperty

至于将值返回给代理,还有 AutoMapper,或者您可以以某种方式公开该字段。

您现在可以为您的应用程序进一步自定义这些包装类,而不必担心在重新生成代理时丢失它。

于 2012-10-04T19:11:27.007 回答