Frage .NET: Ermitteln Sie den Typ der Klasse "this" in ihrer statischen Methode


In einer nicht-statischen Methode könnte ich verwenden this.GetType() und es würde das zurückgeben Type. Wie kann ich das Gleiche bekommen? Type in einer statischen Methode? Natürlich kann ich nicht einfach schreiben typeof(ThisTypeName) weil ThisTypeName ist nur in Laufzeit bekannt. Vielen Dank!


75
2018-01-17 16:14


Ursprung


Antworten:


Wenn Sie nach einem 1-Liner suchen, der entspricht this.GetType() Versuchen Sie Folgendes für statische Methoden.

Type t = MethodBase.GetCurrentMethod().DeclaringType

Obwohl das wahrscheinlich viel teurer ist als nur zu verwenden typeof(TheTypeName).


108
2018-01-17 16:20



Es gibt etwas, das die anderen Antworten nicht ganz geklärt haben und das für Ihre Idee des Typs relevant ist, der nur zur Ausführungszeit verfügbar ist.

Wenn Sie einen abgeleiteten Typ zum Ausführen eines statischen Members verwenden, echt Der Typname wird in der Binärdatei weggelassen. Also kompiliere zum Beispiel diesen Code:

UnicodeEncoding.GetEncoding(0);

Verwenden Sie jetzt ildasm ... Sie werden sehen, dass der Aufruf wie folgt gesendet wird:

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

Der Compiler hat den Aufruf zu aufgelöst Encoding.GetEncoding - Es gibt keine Spur von UnicodeEncoding links. Das macht deine Vorstellung von "dem aktuellen Typus" unsinnig, fürchte ich.


54
2018-01-17 16:33



Eine andere Lösung besteht darin, einen Selbstreferenzierungstyp zu verwenden

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

Dann mache ich in der Klasse, die es erbt, einen selbst referenzierenden Typ:

public class Child: Parent<Child>
{
}

Jetzt ruft der Aufruftyp typeof (TSelfReferenceType) in Parent den Typ des Aufrufers ab und gibt ihn zurück, ohne dass eine Instanz benötigt wird.

Child.GetType();

-Rauben


24
2018-02-16 05:37



Sie können nicht verwenden this in einer statischen Methode, also ist das nicht direkt möglich. Wenn Sie jedoch den Typ eines Objekts benötigen, rufen Sie einfach an GetType darauf und das machen this Instanz ein Parameter, den Sie übergeben müssen, z.

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

Dies scheint jedoch ein schlechtes Design zu sein. Sind Sie sicher, dass Sie den Typ der Instanz selbst innerhalb ihrer eigenen statischen Methode abrufen müssen? Das scheint etwas bizarr. Warum nicht einfach eine Instanzmethode verwenden?

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



Ich verstehe nicht, warum Sie typeof (ThisTypeName) nicht verwenden können. Wenn dies ein nicht generischer Typ ist, sollte dies funktionieren:

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

Wenn es ein generischer Typ ist, dann:

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

Fehle ich etwas Offensichtliches hier?


3
2018-01-17 16:26



Wenn Ihr Mitglied statisch ist, wissen Sie immer zur Laufzeit, zu welchem ​​Typ es gehört. In diesem Fall:

class A
{
  public static int GetInt(){}

}
class B : A {}

Sie können nicht anrufen (bearbeiten: scheinbar, Sie können, siehe Kommentar unten, aber Sie würden immer noch in A anrufen):

B.GetInt();

Da das Element statisch ist, spielt es in Vererbungsszenarien keine Rolle. Ergo, du weißt immer, dass der Typ A ist.


0
2018-01-17 16:23



Für meine Zwecke mag ich @ T-motys Idee. Auch wenn ich seit Jahren "selbst-referenzierende" Informationen verwendet habe, ist es später schwieriger, auf die Basisklasse zu verweisen.

Zum Beispiel (mit @Rob Leclerc Beispiel von oben):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

Die Arbeit mit diesem Muster kann zum Beispiel eine Herausforderung darstellen. Wie gibst du die Basisklasse von einem Funktionsaufruf zurück?

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

Oder beim Typgießen?

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

Also versuche ich es zu vermeiden, wenn ich kann und benutze es wenn ich muss. Wenn Sie müssen, würde ich vorschlagen, dass Sie diesem Muster folgen:

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

Jetzt können Sie (mehr) einfach mit dem arbeiten BaseClass. Es gibt jedoch Zeiten, wie meine aktuelle Situation, in denen die abgeleitete Klasse aus der Basisklasse heraus nicht benötigt wird und die Verwendung von @ M-motys Vorschlag einfach der richtige Ansatz sein könnte.

Die Verwendung von @ M-motys Code funktioniert jedoch nur so lange, wie die Basisklasse keine Instanzkonstruktoren im Aufruf-Stack enthält. Leider verwenden meine Basisklassen Instanzkonstruktoren.

Daher ist hier meine Erweiterungsmethode, die "Instanz" -Konstruktoren der Basisklasse berücksichtigt:

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



BEARBEITEN Diese Methode funktioniert nur, wenn Sie PDB-Dateien mit der ausführbaren Datei / library, as bereitstellen Marknel wies mich darauf hin.

Sonst wird ein riesiges Problem entdeckt: funktioniert gut in der Entwicklung, aber vielleicht nicht in der Produktion.


Nutze die Methode einfach von jedem Ort deines Codes aus:

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