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

2019-01-03 09:25发布

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

8条回答
我命由我不由天
2楼-- · 2019-01-03 10:29

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;
    }
}
查看更多
\"骚年 ilove
3楼-- · 2019-01-03 10:29

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;
}
查看更多
登录 后发表回答