Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Internal Workings of C# Virtual and Override

The topic of how C# virtual and override mechanism works internally has been discussed to death amongst the programmers... but after half an hour on google, I cannot find an answer to the following question (see below):

Using a simple code:

public class BaseClass
{
  public virtual SayNo() { return "NO!!!"; }
}

public class SecondClass: BaseClass
{
  public override SayNo() { return "No."; }
}

public class ThirdClass: SecondClass
{
  public override SayNo() { return "No..."; }
}

class Program
{
  static void Main()
  {
     ThirdClass thirdclass = new ThirdClass();
     string a = thirdclass.SayNo(); // this would return "No..."

     // Question: 
     // Is there a way, not using the "new" keyword and/or the "hide"
     // mechansim (i.e. not modifying the 3 classes above), can we somehow return
     // a string from the SecondClass or even the BaseClass only using the 
     // variable "third"?

     // I know the lines below won't get me to "NO!!!"
     BaseClass bc = (BaseClass)thirdclass;
     string b = bc.SayNo(); // this gives me "No..." but how to I get to "NO!!!"?
  }
}

I think I can't get to the methods of base class or the intermediate derived class simply using the most derived instance (without modifying the method signatures of the 3 classes). But I would like to confirm and cement my understanding...

Thanks.

like image 845
henry000 Avatar asked Apr 15 '09 14:04

henry000


People also ask

How does C language work?

C is what's referred to as a compiled language, meaning you have to use a compiler to turn the code into an executable file before you can run it. The code is written into one or more text files, which you can open, read and edit in any text editor, such as Notepad in Windows, TextEdit on a Mac, and gedit in Linux.

How is C program compiled?

Compilation process in C involves four steps: pre-processing, compiling, assembling, and linking. The preprocessor tool helps in comments removal, macros expansion, file inclusion, and conditional compilation. These commands are executed in the first step of the compilation process.

How code is executed in C?

Loader loads the executable module to the main memory for execution. Linker takes the object code generated by an assembler, as input. Loader takes executable module generated by a linker as input. Linker combines all the object modules of a source code to generate an executable module.

What are the main 4 components of C language?

Components of c program structurePre-processor. variables. Functions. C program statements and expressions.


1 Answers

C# can't do this but it is actually possible in IL using call instead of callvirt. You can thus work around C#'s limitation by using Reflection.Emit in combination with a DynamicMethod.

Here's a very simple example to illustrate how this works. If you really intend to use this, wrap it inside a nice function strive to make it work with different delegate types.

delegate string SayNoDelegate(BaseClass instance);

static void Main() {
    BaseClass target = new SecondClass();

    var method_args = new Type[] { typeof(BaseClass) };
    var pull = new DynamicMethod("pull", typeof(string), method_args);
    var method = typeof(BaseClass).GetMethod("SayNo", new Type[] {});
    var ilgen = pull.GetILGenerator();
    ilgen.Emit(OpCodes.Ldarg_0);
    ilgen.EmitCall(OpCodes.Call, method, null);
    ilgen.Emit(OpCodes.Ret);

    var call = (SayNoDelegate)pull.CreateDelegate(typeof(SayNoDelegate));
    Console.WriteLine("callvirt, in C#: {0}", target.SayNo());
    Console.WriteLine("call, in IL: {0}", call(target));
}

Prints:

callvirt, in C#: No.
call, in IL: NO!!!
like image 72
Konrad Rudolph Avatar answered Sep 19 '22 13:09

Konrad Rudolph