.NET: Определите тип класса" this " в его статическом методе


в нестатическом методе я мог бы использовать this.GetType() и вернется в Type. Как я могу получить то же самое Type в статическом методе? Конечно, я не могу просто написать typeof(ThisTypeName), потому что ThisTypeName известно только в runtime. Спасибо!

8 77

8 ответов:

Если вы ищете 1 лайнер, который эквивалентен this.GetType() для статических методов, попробуйте следующее.

Type t = MethodBase.GetCurrentMethod().DeclaringType

хотя это, вероятно, намного дороже, чем просто с помощью typeof(TheTypeName).

есть что-то, что другие ответы не совсем прояснили, и что имеет отношение к вашей идее типа, доступного только во время выполнения.

если вы используете производный тип для выполнения статического члена, то реальные имя типа опущено в двоичном файле. Так, например, скомпилируйте этот код:

UnicodeEncoding.GetEncoding(0);

теперь используйте ildasm на нем... вы увидите, что вызов испускается следующим образом:

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

компилятор разрешил вызов Encoding.GetEncoding - никаких следов UnicodeEncoding левый. Боюсь, это делает ваше представление о "текущем типе" бессмысленным.

другое решение-использовать тип selfreferecing

//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) внутри родителя будет получать и возвращать тип вызывающего абонента без необходимости экземпляра.

Child.GetType();

-Роб

вы не можете использовать 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());
  }
}

Я не понимаю, почему вы не можете использовать 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>);
    }
}

я упускаю что-то очевидное здесь?

когда ваш член статичен, вы всегда будете знать, какой тип он является частью во время выполнения. В этом случае:

class A
{
  public static int GetInt(){}

}
class B : A {}

вы не можете позвонить (edit: по-видимому, вы можете, см. комментарий ниже, но вы все равно будете звонить в A):

B.GetInt();

поскольку элемент является статическим, он не играет роли в сценариях наследования. Эрго, вы всегда знаете, что тип А.

для моих целей мне нравится идея @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;
    }
}

редактировать Эти методы будут работать только при развертывании 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;
}