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

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

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

4b9b3361

Ответ 1

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

Type t = MethodBase.GetCurrentMethod().DeclaringType

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

Ответ 2

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

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

UnicodeEncoding.GetEncoding(0);

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

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

Компилятор разрешил вызов Encoding.GetEncoding - нет следа UnicodeEncoding слева. Я боюсь, что твоя идея "нынешнего типа" бессмысленна.

Ответ 3

Другим решением является использование типа 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();

Роб

Ответ 4

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

Ответ 5

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

Я пропустил что-то очевидное здесь?

Ответ 6

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

class A
{
  public static int GetInt(){}

}
class B : A {}

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

B.GetInt();

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

Ответ 7

ИЗМЕНИТЬ Эти методы будут работать только при развертывании файлов 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;
}

Ответ 8

В моих целях мне нравится идея @T-moty. Несмотря на то, что я использовал информацию типа "self-referencing type" в течение многих лет, ссылка на базовый класс сложнее сделать позже.

Например (используя пример @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;
    }
}