.NET:以其静态方法确定“此类”的类型


94

在非静态方法中,我可以使用this.GetType()并且它将返回Type。如何通过Type静态方法获得相同的信息?当然,我不能只写,typeof(ThisTypeName)因为ThisTypeName仅在运行时才知道。谢谢!


16
您处于STATIC上下文中,无法编写typeof(ThisTypeName)吗?怎么样?
布鲁诺·雷斯

1
静态方法内部没有类似“运行时”的东西(假设您不是在谈论传递给静态方法的参数)。在这种情况下,您可以简单地说出typeof(RelevantType)。
Manish Basantani 2010年

2
静态方法不能是虚拟的。您已经知道类型了。
汉斯(Hans Passant)2010年

7
抽象的派生类将有很多。基本抽象类具有静态字典<Int,Type>。因此派生类在静态构造函数(dic.Add(N,T))中“注册”自身。是的,我确实知道类型:)我有点懒,不喜欢替换文本,想知道是否可以在运行时确定“ T”。请原谅我的谎言,因为这只是为了简化问题。并且有效;)现在有一个公认的解决方案。谢谢。
Yegor

子类继承其父类的静态方法,不是吗?一个超类静态方法对其所有子类都有用,这是否有意义?静态简单意味着没有实例,那么公共基类中的通用代码原理肯定适用于静态方法和实例方法吗?
马特·康诺利

Answers:


134

如果您要寻找与this.GetType()静态方法等效的1衬管,请尝试以下方法。

Type t = MethodBase.GetCurrentMethod().DeclaringType

尽管这可能比仅使用更昂贵typeof(TheTypeName)


1
这个很好用。谢谢:)并不是那么昂贵,因为它被称为非常罕见。
Yegor

2
令人困惑的是,“昂贵的”贾里德(Jared)表示,它们对于处理器而言很昂贵,通常意味着速度很慢。但他说,“贵得多”意味着放慢速度。除非您正在设计火箭制导系统,否则可能根本不会变慢。
Dan Rosenstark 2010年

1
我已经看到GetCurrentMethod导致一些严重的性能问题。但是由于您只是获取类型,因此可以对其进行缓存。
乔纳森·艾伦,2010年

51
这总是返回实现当前方法的类,而不是子类中被调用的类。
马特·康诺利

3
我想如果代码曾经被移植到不同的类名或其他东西上,避免错误很方便,但是typeof(TheTypeName)无论如何,一个好的重构工具应该可以解决。
Nyerguds

59

还有一些其他答案尚未完全弄清楚,这与您只在执行时可用的类型的想法有关。

如果使用派生类型执行静态成员,则在二进制文件中将省略类型名称。因此,例如,编译以下代码:

UnicodeEncoding.GetEncoding(0);

现在在其上使用ildasm ...您将看到发出的呼叫如下:

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

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


24

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

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

现在,Parent中的调用类型typeof(TSelfReferenceType)将获得并返回调用者的Type,而无需实例。

Child.GetType();

-抢


我已经将其用于单例模式,即Singleton <T> ...静态成员然后可以在错误消息中或其他需要的地方引用typeof(T)。
yoyo

1
你好 我非常喜欢并欣赏此答案,因为它为我提供了一种从静态基本函数中查找子类型的解决方法。
Bill软件工程师

1
好一个。遗憾的是,在C#中,如果没有这么小的代码重复就无法做到这一点。
显示名称


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

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

我在这里错过明显的东西吗?


7
如果您创建了一个从Foo派生的Bar类,然后该类继承了Method1,则此方法将不起作用-然后对Bar.Method1的调用仍将处理typeof(Foo),这是错误的。继承的Method1应该以某种方式知道它在Bar中被派生,然后获取typeof(Bar)。
JustAMartin

0

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

class A
{
  public static int GetInt(){}

}
class B : A {}

您无法致电(编辑:显然,您可以,请参阅下面的评论,但您仍会致电A):

B.GetInt();

因为成员是静态的,所以它在继承方案中不起作用。因此,您始终知道类型是A。


4
可以调用B.GetInt()-至少可以调用它(如果不是私有的),但是编译会将其转换为对A.GetInt()的调用。试试吧!
乔恩·斯基特

请注意乔恩的评论:C#中的默认可见性是私有的,因此您的示例不起作用。
Dan Rosenstark 2010年

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

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

1
StackTrace仅在Debug版本中可用
markmnl

不正确:当您还在发布模式下部署.pdb文件时,StackTrace将可用。stackoverflow.com/questions/2345957/...
T-moty

我明白你的意思。仅当部署PDB文件时,该方法才有效是不可接受的。我将编辑答案
T-moty
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.