开发者

.NET: Determine the type of “this” class in its static method

In a non-static method I could use this.GetType() and it would return the Type. How can I get t开发者_如何学JAVAhe same Type in a static method? Of course, I can't just write typeof(ThisTypeName) because ThisTypeName is known only in runtime. Thanks!


If you're looking for a 1 liner that is equivalent to this.GetType() for static methods, try the following.

Type t = MethodBase.GetCurrentMethod().DeclaringType

Although this is likely much more expensive than just using typeof(TheTypeName).


There's something that the other answers haven't quite clarified, and which is relevant to your idea of the type only being available at execution time.

If you use a derived type to execute a static member, the real type name is omitted in the binary. So for example, compile this code:

UnicodeEncoding.GetEncoding(0);

Now use ildasm on it... you'll see that the call is emitted like this:

IL_0002:  call       class [mscorlib]System.Text.Encoding 
[mscorlib]System.Text.Encoding::GetEncoding(int32)

The compiler has resolved the call to Encoding.GetEncoding - there's no trace of UnicodeEncoding left. That makes your idea of "the current type" nonsensical, I'm afraid.


Another solution is to use a selfreferecing type

//My base class
//I add a type to my base class use that in the 
//static method to check the type of the caller.
public class Parent<TSelfReferenceType>
{
    public static Type GetType()
    {
        return typeof(TSelfReferenceType);
    }
}

Then in the class that inherits it, I make a self referencing type:

public class Child: Parent<Child>
{
}

Now the call type typeof(TSelfReferenceType) inside Parent will get and return the Type of the caller without the need of an instance.

Child.GetType();


You can't use this in a static method, so that's not possible directly. However, if you need the type of some object, just call GetType on it and make the this instance a parameter that you have to pass, e.g.:

public class Car {
  public static void Drive(Car c) {
    Console.WriteLine("Driving a {0}", c.GetType());
  }
}

This seems like a poor design, though. Are you sure that you really need to get the type of the instance itself inside of its own static method? That seems a little bizarre. Why not just use an instance method?

public class Car {
  public void Drive() { // Remove parameter; doesn't need to be static.
    Console.WriteLine("Driving a {0}", this.GetType());
  }
}


I don't understand why you cannot use typeof(ThisTypeName). If this is a non-generic type, then this should work:

class Foo {
   static void Method1 () {
      Type t = typeof (Foo); // Can just hard code this
   }
}

If it's a generic type, then:

class Foo<T> {
    static void Method1 () {
       Type t = typeof (Foo<T>);
    }
}

Am I missing something obvious here?


When your member is static, you will always know what type it is part of at runtime. In this case:

class A
{
  public static int GetInt(){}

}
class B : A {}

You cannot call (edit: apparently, you can, see comment below, but you would still be calling into A):

B.GetInt();

because the member is static, it does not play part in inheritance scenarios. Ergo, you always know that the type is A.


For my purposes, I like @T-moty's idea. Even though I have used "self-referencing type" information for years, referencing the base class is harder to do later.

For example (using @Rob Leclerc example from above):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

Working with this pattern can be challenging, for example; how do you return the base class from a function call?

public Parent<???> GetParent() {}

Or when type casting?

var c = (Parent<???>) GetSomeParent();

So, I try to avoid it when I can, and use it when I must. If you must, I would suggest that you follow this pattern:

class BaseClass
{
    // All non-derived class methods goes here...

    // For example:
    public int Id { get; private set; }
    public string Name { get; private set; }
    public void Run() {}
}

class BaseClass<TSelfReferenceType> : BaseClass
{
    // All derived class methods goes here...

    // For example:
    public TSelfReferenceType Foo() {}
    public void Bar(TSelfRefenceType obj) {}
}

Now you can (more) easily work with the BaseClass. However, there are times, like my current situation, where exposing the derived class, from within the base class, isn't needed and using @M-moty's suggestion just might be the right approach.

However, using @M-moty's code only works as long as the base class doesn't contain any instance constructors in the call stack. Unfortunately my base classes do use instance constructors.

Therefore, here's my extension method that take into account base class 'instance' constructors:

public static class TypeExtensions
{
    public static Type GetDrivedType(this Type type, int maxSearchDepth = 10)
    {
        if (maxSearchDepth < 0)
            throw new ArgumentOutOfRangeException(nameof(maxSearchDepth), "Must be greater than 0.");

        const int skipFrames = 2;  // Skip the call to self, skip the call to the static Ctor.
        var stack = new StackTrace();
        var maxCount = Math.Min(maxSearchDepth + skipFrames + 1, stack.FrameCount);
        var frame = skipFrames;

        // Skip all the base class 'instance' ctor calls. 
        //
        while (frame < maxCount)
        {
            var method = stack.GetFrame(frame).GetMethod();
            var declaringType = method.DeclaringType;

            if (type.IsAssignableFrom(declaringType))
                return declaringType;

            frame++;
        }

        return null;
    }
}


EDIT This methods will works only when you deploy PDB files with the executable/library, as markmnl pointed out to me.

Otherwise will be a huge issue to be detected: works well in developement, but maybe not in production.


Utility method, simply call the method when you need, from every place of your code:

public static Type GetType()
{
    var stack = new System.Diagnostics.StackTrace();

    if (stack.FrameCount < 2)
        return null;

    return (stack.GetFrame(1).GetMethod() as System.Reflection.MethodInfo).DeclaringType;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜