不使用接口删除冗余的C#代码

时间:2012-10-04 18:53:29

标签: c# wcf

请考虑两个限制 -

  1. 无法将MyProperty移动到界面或抽象类。
  2. FooEventHandler是一个dotnet框架方法,因此无法更改参数类型。
  3. 我在几个班级中定义了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
        }
    

    感谢您的帮助。

5 个答案:

答案 0 :(得分: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 :(得分: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 {}

答案 2 :(得分:3)

我的第一个想法是在事件处理程序中使用反射:

public object FooEventHandler(object obj)
{
    obj.GetType().GetProperty("MyProperty").SetValue(obj, "updated", null);
    return obj;
}

答案 3 :(得分:3)

使用反射,您可以检查这些条件,然后设置值:

  1. 具有预期的属性MyProperty
  2. MyProperty的类型为string
  3. MyProperty有一个二传手
  4. 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;
    }
    

答案 4 :(得分:1)

修改
蒂姆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

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

至于将值恢复到代理,还有AutoMapper,或者您可以以某种方式公开字段。

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