104

在我可以使用的非静态方法中this.GetType(),它会返回Type. 我怎样才能Type在静态方法中得到相同的结果?当然,我不能只写typeof(ThisTypeName),因为ThisTypeName只在运行时才知道。谢谢!

4

8 回答 8

148

如果您正在寻找与this.GetType()静态方法等效的 1 班轮,请尝试以下操作。

Type t = MethodBase.GetCurrentMethod().DeclaringType

尽管这可能比仅使用typeof(TheTypeName).

于 2010-01-17T16:20:39.370 回答
59

其他答案还没有完全澄清,这与您认为类型仅在执行时可用的想法有关。

如果您使用派生类型来执行静态成员,则二进制文件中会省略实际类型名称。例如,编译这段代码:

UnicodeEncoding.GetEncoding(0);

现在在它上面使用 ildasm ......你会看到调用是这样发出的:

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

编译器已经解决了对的调用Encoding.GetEncoding- 没有UnicodeEncoding留下的痕迹。恐怕这使您对“当前类型”的想法变得荒谬。

于 2010-01-17T16:33:55.627 回答
28

另一种解决方案是使用自引用类型

//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);
    }
}

然后在继承它的类中,我创建了一个自引用类型:

public class Child: Parent<Child>
{
}

现在typeof(TSelfReferenceType)Parent 中的调用类型将Type在不需要实例的情况下获取并返回调用者的。

Child.GetType();
于 2011-02-16T05:37:53.557 回答
5

您不能this在静态方法中使用,因此无法直接使用。但是,如果您需要某个对象的类型,只需调用GetType它并使this实例成为您必须传递的参数,例如:

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

不过,这似乎是一个糟糕的设计。你确定你真的需要在它自己的静态方法中获取实例本身的类型吗?这似乎有点奇怪。为什么不只使用实例方法?

public class Car {
  public void Drive() { // Remove parameter; doesn't need to be static.
    Console.WriteLine("Driving a {0}", this.GetType());
  }
}
于 2010-01-17T16:16:49.927 回答
3

我不明白为什么你不能使用 typeof(ThisTypeName)。如果这是一个非泛型类型,那么这应该工作:

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

如果它是泛型类型,则:

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

我在这里遗漏了一些明显的东西吗?

于 2010-01-17T16:26:18.120 回答
0

当您的成员是静态的时,您将始终知道它在运行时属于什么类型。在这种情况下:

class A
{
  public static int GetInt(){}

}
class B : A {}

你不能打电话(编辑:显然,你可以,见下面的评论,但你仍然会打电话给A):

B.GetInt();

因为成员是静态的,所以它不参与继承场景。因此,你总是知道类型是 A。

于 2010-01-17T16:23:19.063 回答
0

编辑 此方法仅在您使用可执行文件/库部署 PDB 文件时才有效,正如markmnl向我指出的那样。

否则将是一个需要检测的大问题:在开发中运行良好,但在生产中可能不行。


实用方法,只需在需要时从代码的每个位置调用该方法:

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;
}
于 2013-09-17T13:54:07.930 回答
0

出于我的目的,我喜欢@T-moty 的想法。尽管我多年来一直使用“自引用类型”信息,但以后引用基类更难了。

例如(使用上面的@Rob Leclerc 示例):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

例如,使用这种模式可能具有挑战性;如何从函数调用中返回基类?

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

或者当类型转换?

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

因此,我尽量避免使用它,并在必要时使用它。如果必须,我建议您遵循以下模式:

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) {}
}

现在您可以(更)轻松地使用BaseClass. 但是,有时,就像我目前的情况一样,不需要从基类中公开派生类,而使用@M-moty 的建议可能是正确的方法。

但是,使用@M-moty 的代码仅在基类不包含调用堆栈中的任何实例构造函数的情况下才有效。不幸的是,我的基类确实使用了实例构造函数。

因此,这是我的扩展方法,它考虑了基类“实例”构造函数:

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;
    }
}
于 2016-04-28T12:30:01.817 回答