Pregunta .NET: determina el tipo de clase "this" en su método estático


En un método no estático que podría usar this.GetType() y devolvería el Type. ¿Cómo puedo obtener lo mismo? Type en un método estático? Por supuesto, no puedo simplemente escribir typeof(ThisTypeName) porque ThisTypeName es conocido solo en tiempo de ejecución. ¡Gracias!


75
2018-01-17 16:14


origen


Respuestas:


Si está buscando un forro 1 que sea equivalente a this.GetType() para métodos estáticos, intente lo siguiente.

Type t = MethodBase.GetCurrentMethod().DeclaringType

Aunque esto es probablemente mucho más costoso que solo usar typeof(TheTypeName).


108
2018-01-17 16:20



Hay algo que las otras respuestas no han aclarado del todo, y que es relevante para su idea de que el tipo solo está disponible en el momento de la ejecución.

Si usa un tipo derivado para ejecutar un miembro estático, el real El nombre del tipo se omite en el binario. Entonces, por ejemplo, compila este código:

UnicodeEncoding.GetEncoding(0);

Ahora usa ildasm en él ... verás que la llamada se emite así:

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

El compilador resolvió la llamada a Encoding.GetEncoding - No hay rastro de UnicodeEncoding izquierda. Eso hace que tu idea del "tipo actual" no tenga sentido, me temo.


54
2018-01-17 16:33



Otra solución es usar un tipo autoreferente

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

Luego, en la clase que lo hereda, hago un tipo de auto referenciado:

public class Child: Parent<Child>
{
}

Ahora el tipo de llamada typeof (TSelfReferenceType) dentro de Parent obtendrá y devolverá el tipo de la persona que llama sin necesidad de una instancia.

Child.GetType();

-Robar


24
2018-02-16 05:37



No puedes usar this en un método estático, por lo que no es posible directamente. Sin embargo, si necesita el tipo de algún objeto, simplemente llame GetType en él y hacer el this ejemplo, un parámetro que debe pasar, p. ej .:

public class Car {
  public static void Drive(Car c) {
    Console.WriteLine("Driving a {0}", c.GetType());
  }
}

Esto parece un diseño pobre, sin embargo. ¿Estás seguro de que realmente necesitas obtener el tipo de instancia propia dentro de su propio método estático? Eso parece un poco extraño. ¿Por qué no usar un método de instancia?

public class Car {
  public void Drive() { // Remove parameter; doesn't need to be static.
    Console.WriteLine("Driving a {0}", this.GetType());
  }
}

6
2018-01-17 16:16



No entiendo por qué no puedes usar typeof (ThisTypeName). Si este es un tipo no genérico, entonces esto debería funcionar:

class Foo {
   static void Method1 () {
      Type t = typeof (Foo); // Can just hard code this
   }
}

Si es un tipo genérico, entonces:

class Foo<T> {
    static void Method1 () {
       Type t = typeof (Foo<T>);
    }
}

¿Me estoy perdiendo algo obvio aquí?


3
2018-01-17 16:26



Cuando su miembro es estático, siempre sabrá de qué tipo es parte en tiempo de ejecución. En este caso:

class A
{
  public static int GetInt(){}

}
class B : A {}

No puede llamar (editar: aparentemente, puede ver el comentario a continuación, pero aún estaría llamando a A):

B.GetInt();

porque el miembro es estático, no juega parte de los escenarios de herencia. Ergo, siempre sabes que el tipo es A.


0
2018-01-17 16:23



Para mis propósitos, me gusta la idea de @T-moty. Aunque utilicé la información del "tipo de autorreferencia" durante años, hacer referencia a la clase base es más difícil de hacer más adelante.

Por ejemplo (usando el ejemplo de @Rob Leclerc de arriba):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

Trabajar con este patrón puede ser desafiante, por ejemplo; ¿cómo se devuelve la clase base de una llamada a función?

public Parent<???> GetParent() {}

O cuando el tipo de fundición?

var c = (Parent<???>) GetSomeParent();

Por lo tanto, trato de evitarlo cuando puedo, y usarlo cuando debo. Si debe hacerlo, le sugiero que siga este patrón:

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

Ahora puede (más) trabajar fácilmente con el BaseClass. Sin embargo, hay momentos, como mi situación actual, donde no es necesario exponer la clase derivada, desde dentro de la clase base, y usar la sugerencia de @M-moty podría ser el enfoque correcto.

Sin embargo, usar el código de @M-moty solo funciona siempre que la clase base no contenga ningún constructor de instancia en la pila de llamadas. Lamentablemente, mis clases base usan constructores de instancias.

Por lo tanto, aquí está mi método de extensión que tiene en cuenta los constructores de 'instancia' de la clase base:

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
2018-04-28 12:30



EDITAR Este método funcionará solo cuando implemente archivos PDB con el ejecutable / biblioteca, como markmnl me señaló.

De lo contrario, será un gran problema para detectar: ​​funciona bien en el desarrollo, pero tal vez no en la producción.


Método de utilidad, simplemente llame al método cuando lo necesite, desde cualquier lugar de su código:

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