How to force call C # method

I have a class that is generated by some tool, so I cannot change it. The generated class is very simple (no interface, no virtual methods):

class GeneratedFoo { public void Write(string p) { /* do something */ } } 

In the C # project, we want to provide a way so that we can connect to another MyFoo implementation. So I'm going to make MyFoo from GeneratedFoo

 class MyFoo : GeneratedFoo { public new void Write(string p) { /* do different things */ } } 

Then I have a CreateFoo method that will either return an instance of the GeneratedFoo class, or MyFoo. However, it always calls a method in GeneratedFoo.

 GeneratedFoo foo = CreateFoo(); // if this returns MyFoo, foo.Write("1"); // it stills calls GeneratedFoo.Write 

This is expceted as it is not a virtual method. But I am wondering if there is a way (possibly a hack) to force it to call a derived method.

Thanks,
Ian

+7
inheritance design c # class
source share
7 answers

Without the ability to make the method virtual, no. A non-virtual method is statically linked at compile time and cannot be modified.

+6
source share

Adam gave you the answer (correct). Now is the time for hacking that you requested :)

 class BaseFoo { public void Write() { Console.WriteLine("Hello simple world"); } } class DerFoo : BaseFoo { public void Write() { Console.WriteLine("Hello complicated world"); } } public static void Main() { BaseFoo bs = new DerFoo(); bs.Write(); bs.GetType().GetMethod("Write").Invoke(bs, null); } 

Prints out:

 Hello simple world
 Hello complicated world
+22
source share

Write down an extension method that provides a safe transition to your derived type and instead calls the method instead of this reference.

 public static class Extensions { public static void WriteFoo(this GeneratedFoo foo, string p) { MyFoo derived = foo as MyFoo; if (derived != null) { derived.Write(p); } else { foo.Write(p); } } } 

then call it with

 GeneratedFoo unknownFoo; unknownFoo.WriteFoo("win"); 

NB : this is a dirty hack. A clearer solution is to ask yourself why you need to use the new modifier in the first place. Overloading the Write(p) value will make your code confusing for maintainers. You could just as easily declare it public void WriteToTarget() or something more specific to avoid this confusion in the first place.

+6
source share

Using "new" in a method is not overriding; it is hidden by the original method. This is completely different from polymorphism, and it should be avoided, its sole purpose is to covariate / contradict between methods that perform an identical function (e.g. public Foo Clone () and public new Bar Clone ();). Another goal is legacy code, when an identical named method is added to a base class that you do not have, and cannot change the method name at this time.

Although both methods use the same name, they are completely separate methods, it occupies another slot in the class method table, where overriding replaces the existing method in the class method table.

My solution would be to use an interface like IFoo, and either edit the created class, or use a proxy class that delegates all calls to its methods to the GeneratedFoo instance to implement IFoo.

 public DelegatingFoo : IFoo { private GeneratedFoo foo; public DelegatingFoo(GeneratedFoo foo) { this.foo = foo; } public void Write(string p) { foo.Write(p); } } 
+3
source share

If the generated class does not have a virtual method, this is not possible. If you can change the tool to generate the Write method as virtual, then in MyFoo use the override keyword instead of new to qualify the Write method. The second option is to write a script / macro to modify the generated code of GeneratedFoo after running the tool to enter the "virtual" string before the desired methods as part of the build process.

+1
source share

How about a custom FX cop rule added to your build system?

0
source share

An approach you could use was to actually define several new classes, all of which were derived from GeneratedFoo; eg:

 public class MyFooBase : GeneratedFoo { public virtual void MyMethod() { ... } } public class MyFoo1 : MyFooBase { ... } public class MyFoo2 : MyFooBase { ... } 

This will allow you to essentially add virtual methods to your generated class.

-one
source share

All Articles