.NET: Определите тип класса «this» в его статическом методе. - PullRequest
86 голосов
/ 17 января 2010

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

Ответы [ 8 ]

123 голосов
/ 17 января 2010

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

Type t = MethodBase.GetCurrentMethod().DeclaringType

Хотя это, вероятно, намного дороже, чем просто использование typeof(TheTypeName).

58 голосов
/ 17 января 2010

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

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

UnicodeEncoding.GetEncoding(0);

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

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

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

24 голосов
/ 16 февраля 2011

Другое решение заключается в использовании самореферентного типа

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

Child.GetType();

1010 * Роб *

6 голосов
/ 17 января 2010

Вы не можете использовать 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 голосов
/ 17 января 2010

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

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

0 голосов
/ 28 апреля 2016

В моих целях мне нравится идея @ 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 голосов
/ 17 сентября 2013

EDIT Этот метод будет работать только при развертывании файлов 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;
}
0 голосов
/ 17 января 2010

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

class A
{
  public static int GetInt(){}

}
class B : A {}

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

B.GetInt();

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...