3

I have a class that declares a virtual method. However the specific implementations of this method do not explicitly refer to "this" object. They just return a value that is specific for that class.

So one might consistently desire to call this method not only on a specific object but also on the class itself. Since this is of course not possible on the syntactic level, I think it should be at least possible through reflection. That is, I want to iterate through all the classes in my assembly and determine which class returns which value as the response from the said method.

But my naive approach failed with a null reference exception when trying to invoke the method. Why? I expected it to succeed because I have used a concrete class to identify the concrete overridden method, so the "this" object and its virtual method table is not needed to resolve the method.

How can I make it work? (of course excluding the "solution" to define a second truly static method that returns the same value).

using System;
using System.Reflection;

namespace StaticInvoke
{
    public abstract class Foo
    {
        public abstract string StaticValue {get;}
    }

    public class MyFirstFoo: Foo
    {
        public override string StaticValue {get {return "A first attempt to foo-ize Foo.";}}
    }

    class Program
    {
        public static void Main(string[] args)
        {
            Type myFirstFooType = typeof(MyFirstFoo);
            PropertyInfo myFirstStaticValueProperty = myFirstFooType.GetProperty("StaticValue");
            MethodInfo myFirstStaticValueMethod = myFirstStaticValueProperty.GetGetMethod();

            string result = (string)myFirstStaticValueMethod.Invoke(null, null);

            Console.WriteLine("MyFirstFoo.StaticValue == "+result);

            Console.Write("Press any key to continue . . . ");
            Console.ReadKey(true);
        }
    }
}
4
  • You always need an instance to access instance members. As you already found out, you can retrieve metadata about instance members without providing one, but that is it. Commented Oct 7, 2019 at 6:11
  • Also please check the code you provided here, the public modifier is missing and a NullReferenceException is thrown because your StaticValue member is a property but you search for a method myFirstFooType.GetMethod. dotnetfiddle.net/kVLQYD Commented Oct 7, 2019 at 6:17
  • You are getting a NullReferenceException with this code because StaticValue is a property not a method (and the MethodInfo is null). However you would get a similar TargetInvocationException if it was done correctly. Commented Oct 7, 2019 at 6:18
  • @thehennyy and Mike Zboray: my bad and good point. The code has evolved from a method originally instead of a property, so I missed that this breaks the method request. Commented Oct 7, 2019 at 7:05

3 Answers 3

5

However the specific implementations of this method do not explicitly refer to "this" object.

Yes, the c# language does not require prefixing this because it's not necessary.

So one might consistently desire to call this method not only on a specific object but also on the class itself.

That cannot be done. C# does not allow both an instance method and a static method with the same name. So the desire cannot be solved and another solution is necessary.

Since this is of course not possible on the syntactic level, I think it should be at least possible through reflection.

Reflection only operates on what is allowed. If you can't have a both a static and instance with the same name, Reflection won't solve it.

But my naive approach failed with a null reference exception when trying to invoke the method. Why?

Because you called an Instance Method on null. Your example could be simplified to:

(null as string).Count()

Same thing, without reflection. You cannot call Count() on null.

I expected it to succeed because I have used a concrete class to identify the concrete overridden method, so the "this" object and its virtual method table is not needed to resolve the method.

You still can't call methods on a Null object regardless of how you cast it.

How can I make it work? (of course excluding the "solution" to define a second truly static method that returns the same value).

You cannot based on your requirement of:

call this method not only on a specific object but also on the class itself.

Update 1:

Rather my requirement is to obtain the obviously static information contained in the instance method body (the value) in a static context, whatever the solution may be.

This is really confusing, so here is example code:

public class Person
{
  // So this is "Static Inforamtion"
  public static int StaticInformation()
  {
    return 1;
  }

  // instance method
  public static int InstanceMethod()
  {
    return StaticInformation();
  }
}

public static class StaticClass
{
  public static int StaticContext()
  {
    return Person.InstanceMethod();
  }
}

This is assumed based on your statement. This is the best I can do to describe your sentence as code. Saying static information should mean to most if not all .Net developers, a Method, Property or Field marked as Static. However, it's extremely ambiguous to state static information contained in the instance body. What is body? Body of the instance method or body of the class?

I'd also wonder WHY anyone would want to do this. It seems like this is just a theoretical problem and wouldn't solve any real world scenarios. Under what situation in C# would I have a method pointer of sorts (MethodInfo) and want to invoke it without knowing if I do or do not have an instance? And if the same result is expected, then why the need for an Instance method at all?

Sign up to request clarification or add additional context in comments.

5 Comments

Nice answer, and lot of misconceptions put to rest
Thank you for the answer, but I am afraid that you have misconceived my underlying requirement. Although I have tried to satisfy my requirement by calling an instance method on null, I do not require to do this. Rather my requirement is to obtain the obviously static information contained in the instance method body (the value) in a static context, whatever the solution may be.
Erik, I mentioned "static information contained in the instance method body" because I meant static information contained in the "Body of the instance method", to put it in your words. How can that be ambiguous? But I think I know what you mean to say: you are not supposed to obtain that information in c# because it would be too difficult to incorporate in the language. Accepted. But please acknowledge that it is a valid requirement to avoid duplicating of static (in the sense of known at compile-time) information once in an instance method and once in a class method.
So my last point then stands, why have an Instance method if it's return a static value... always use the static value, that's the point.
Because I also want to be able to get this information based on a given concrete object. Sorry if this sounds esoteric to you, but it is part of a bigger concept I didn't want to explain at length here.
4

This is possible but not without some abuse of the reflection system. I am posting it more for informational purposes because I think it illustrates some interesting parts of how C# and .NET work. However I would caution this is extremely brittle and definitely an off-label use of reflection.

What we need to be able to do here is two fold. One is pass a null receiver to an instance method. This is possible via mechanisms like CreateDelegate which can transform an instance invocation into a static invocation where the first parameter is the instance which this will refer to (often called the receiver). The interesting thing about .NET is that on a low-level all methods are static; instance methods have the first parameter slot reserved for the this reference available in the method.

However there is another is issue. You also want to make what is effectively a non-virtual call on a virtual method. The C# compiler exposes this only in very limited scenarios, for example when invoking a method via the base reference. To make a non-virtual call directly the only way is to emit the Call opcode (instead of CallVirt) in manually generated IL.

static void Main(string[] args)
{
    Type myFirstFooType = typeof(MyFirstFoo);

    // locate the underlying methodinfo, properties have get and set methods.
    PropertyInfo myFirstStaticValueMethod = myFirstFooType.GetProperty("StaticValue");
    MethodInfo getMethod = myFirstStaticValueMethod.GetGetMethod();

    // we need to generate a method call that is non-virtual to a virtual method
    // this is normally not allowed in C# because it is prone to error and brittle.
    // Here we directly emit IL to do so.
    var method = new DynamicMethod("NonVirtualGetter", typeof(string), Type.EmptyTypes, typeof(MyFirstFoo), true);
    var ilgen = method.GetILGenerator();
    ilgen.Emit(OpCodes.Ldnull); // load a null value for the receiver
    ilgen.Emit(OpCodes.Call, getMethod); // invoke the getter method
    ilgen.Emit(OpCodes.Ret);

    // generate a delgate to the dynamic method.
    var getter = (Func<string>)method.CreateDelegate(typeof(Func<string>));
    string result = getter();

    Console.WriteLine("MyFirstFoo.StaticValue == " + result);
}

5 Comments

This is pretty cool, but I'm not sure circumventing c# limitations via MSIL/CIL is technically a valid c# solution... if you catch my drift :)
@Mike Zboray: the solution looks interesting, but when I try it, I get a System.Security.VerificationException ("Operation could destabilize the runtime"). Although this might encourage the cynics, I prefer to believe that the devil won't prepare a barbecue with my soul everytime I am doing something that is not supposed to be done. So is there any way to fix this "security issue", like a "yeah, but I know what I am doing" switch in the compiler options?
@oliver I tried this with the code you supplied but maybe that is over simplified. I made a slight tweak to skip visibility checks (that's the true for the last parameter to the DynamicMethod constructor). IL verification is not something that you can skip AFAIK. The CLR requires all IL be verified.
Still no luck... Framework version is 4.5.2 by the way.
@oliver I see, for some reason it was working under .net core, but not .net framework. However it seems like with the additional change I made it is working under .net framework as well. I think this should give you a sense of how brittle this really is and how it depends on some quirky internals of how .net works.
-1

I have decided to resolve the problem the other way around. If the information inside StaticValue is static, then I will keep it truly static.

public abstract class Foo
{
    public string StaticValue 
    {
        get
        {
            FieldInfo targetField = GetType().GetField("staticValue");
            return (string)targetField.GetValue(null);
        }
    }
}

public class MyFirstFoo: Foo
{
    public static string staticValue = "A first attempt to foo-ize Foo.";
}

public class MySecondFoo: Foo
{
    public static string staticValue = "A second attempt to foo-ize Foo.";
}

So when I iterate through all my foo classes in my assembly by reflection, I can simply get the "staticValue" field from each, whereas if I already have a specific Foo object, I might just call the method "StaticValue()".

The ugly thing about this is, of course, that the compiler can't check if a specific Foo class defines the field "staticValue". Making it a static method instead doesn't help either because there is no such thing as a static virtual method or a static interface method in C#. So my solution seems to be the only reasonable one.

2 Comments

An alternative solution is to put the data in attributes on the class. Sure, none of the suggested solutions is enforced by the compiler, but I'm not quite sure why that is a requirement. Having some kind of convention for this is not unusual for a library. Simply have the library validate that the derived class has the required data available by whatever convention you see fit (static property, static field, attribute, etc.)
@MikeZboray: well if I write a new class of that kind, and this class is probably not used very often, I would find it very handy if the compiler would be able to check the compliance to this pretty simply convention. But you are right in that I put too much emphasis on that little detail. Maybe it is also because I am testing my code mainly on an ad-hoc/on-the-fly basis, rather than testing it systematically. So the whole problem is probably due to a flaw of my development practice.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.