C# .NET:在其静态方法中确定“this”类的类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2081612/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:21:19  来源:igfitidea点击:

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

c#.nettypesstatic-methods

提问by Yegor

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

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

采纳答案by JaredPar

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

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

Type t = MethodBase.GetCurrentMethod().DeclaringType

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

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

回答by John Feminella

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

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

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

回答by Teun D

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):

你不能打电话(编辑:显然,你可以,见下面的评论,但你仍然会打电话给 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.

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

回答by Tarydon

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

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

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?

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

回答by Jon Skeet

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 realtype 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:

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

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 UnicodeEncodingleft. That makes your idea of "the current type" nonsensical, I'm afraid.

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

回答by Rob Leclerc

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.

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

Child.GetType();

-Rob

-抢

回答by T-moty

EDITThis methods will works only when you deploy PDB files with the executable/library, as markmnlpointed out to me.

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

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

回答by Kabuo

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.

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

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

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

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.

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

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.

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

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