Remove redundant C # code without using an interface

Please consider two limitations -

  • Cannot move MyProperty to an interface or abstract class.
  • FooEventHandler is a dotnet infrastructure method, so it cannot change the parameter type.

I have MyProperty defined in several classes.

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

The FooEventHandler method updates this property for all parameters that it receives.

 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; } 

And the FooEventHandler is called multiple times -

 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); } 

Please suggest a way to remove redundant code in Foo, considering, first of all, two limitations.

To be more precise, I ran into this problem when using ParameterInspector in WCF. I am trying to change the properties of all requests intercepted here, and should have written a Switch Case based on operationName.

Classes A, B, C, D , as mentioned above, are proxies. Therefore, I do not want to change them in the first place. Since the Service Reference update will overwrite my changes in iterface.

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

Thank you for your help.

+4
source share
5 answers

In fact, you have classes that implement the interface to make things easier. The key is that the generated service reference classes are partial , which means you can do this in a separate file that will not be overwritten when restoring the code:

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

Where is IMyProperty :

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

Then you can change your FooEventHandler method to take IMyProperty , or take an object and check obj is IMyProperty (or use as , so the check is done only once). This allows you to use the property simply, without any reflection or dynamic complexity, and the impact of the performance of these methods on the performance of the execution.

+10
source

Assuming dynamic , you can:

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

This will happen if MyProperty does not exist on obj .

Tested:

 [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 {} 
+5
source

My first thought was to use reflection in an event handler:

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

Using reflection, you can check these conditions, and then set the value:

  • Expected Property MyProperty
  • MyProperty is of type string
  • MyProperty has a setter

.

 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; } 
+3
source

Edit
Tim S's answer is probably the easiest and safest. However, the partial class must be in the same assembly. If for some reason you cannot edit the assembly containing proxy classes, you can still do it.

Original answer

This may be a bit overwhelming.

Create a new interface

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

Add AWrapper / BWrapper and CWrapper . There are two different ways to do this. I will show only A , because the rest should be easy from there.

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

or

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

The advantage of the second is that you can use AWrapper anywhere you can use A

In any case, you will need to find a way to get the values ​​from your shell into your Proxy class. You can use something like AutoMapper to set properties or pass it as a constructor parameter, save it in a field, and implement IProxyWrapper.MyProperty to wrap A.MyProperty .

As for returning values ​​to the proxy server, AutoMapper reappears, or you can open the field somehow.

Now you can configure these wrapper classes for your application without fear of losing it when updating your proxies.

+1
source

Source: https://habr.com/ru/post/1437866/


All Articles