Pertanyaan .NET: Tentukan jenis kelas "ini" dalam metode statisnya


Dalam metode non-statis yang bisa saya gunakan this.GetType() dan itu akan mengembalikan Type. Bagaimana saya bisa mendapatkan yang sama Type dalam metode statis? Tentu saja, saya tidak bisa menulis typeof(ThisTypeName) karena ThisTypeName hanya diketahui dalam waktu proses. Terima kasih!


75
2018-01-17 16:14


asal


Jawaban:


Jika Anda mencari 1 liner yang setara dengan this.GetType() untuk metode statis, coba yang berikut ini.

Type t = MethodBase.GetCurrentMethod().DeclaringType

Meskipun ini mungkin jauh lebih mahal daripada hanya menggunakan typeof(TheTypeName).


108
2018-01-17 16:20



Ada sesuatu yang jawaban lain belum cukup diklarifikasi, dan yang relevan dengan ide Anda tentang jenis hanya tersedia pada waktu eksekusi.

Jika Anda menggunakan tipe turunan untuk mengeksekusi anggota statis, maka nyata nama jenis dihilangkan dalam biner. Jadi misalnya, kompilasi kode ini:

UnicodeEncoding.GetEncoding(0);

Sekarang gunakan ildasm di atasnya ... Anda akan melihat bahwa panggilan itu dipancarkan seperti ini:

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

Compiler telah menyelesaikan panggilan ke Encoding.GetEncoding - tidak ada jejak UnicodeEncoding kiri. Itu membuat ide Anda tentang "tipe saat ini" tidak masuk akal, saya khawatir.


54
2018-01-17 16:33



Solusi lain adalah menggunakan jenis 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);
    }
}

Kemudian di kelas yang mewarisi itu, saya membuat jenis referensi sendiri:

public class Child: Parent<Child>
{
}

Sekarang jenis panggilan typeof (TSelfReferenceType) di dalam Parent akan mendapatkan dan mengembalikan Type dari pemanggil tanpa perlu sebuah instance.

Child.GetType();

-Rampok


24
2018-02-16 05:37



Anda tidak bisa menggunakannya this dalam metode statis, jadi itu tidak mungkin secara langsung. Namun, jika Anda membutuhkan jenis objek, cukup hubungi GetType di atasnya dan membuat this contoh parameter yang harus Anda lewati, misalnya:

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

Ini sepertinya desain yang buruk. Apakah Anda yakin bahwa Anda benar-benar perlu mendapatkan jenis instance itu sendiri di dalam metode statisnya sendiri? Kelihatannya sedikit aneh. Mengapa tidak menggunakan metode instan saja?

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



Saya tidak mengerti mengapa Anda tidak bisa menggunakan typeof (ThisTypeName). Jika ini adalah tipe non-generik, maka ini harus berfungsi:

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

Jika itu tipe generik, maka:

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

Apakah saya kehilangan sesuatu yang jelas di sini?


3
2018-01-17 16:26



Ketika anggota Anda statis, Anda akan selalu tahu jenis apa itu bagian dari saat runtime. Pada kasus ini:

class A
{
  public static int GetInt(){}

}
class B : A {}

Anda tidak dapat menelepon (sunting: rupanya, Anda dapat, lihat komentar di bawah ini, tetapi Anda masih akan menelepon ke A):

B.GetInt();

karena anggotanya statis, ia tidak berperan dalam skenario pewarisan. Ergo, kamu selalu tahu bahwa tipenya adalah A.


0
2018-01-17 16:23



Untuk tujuan saya, saya suka ide @ T-moty. Meskipun saya telah menggunakan informasi "self-reference type" selama bertahun-tahun, referensi kelas dasar lebih sulit dilakukan nantinya.

Misalnya (menggunakan contoh @Rob Leclerc dari atas):

public class ChildA: Parent<ChildA>
{
}

public class ChildB: Parent<ChildB>
{
}

Bekerja dengan pola ini bisa menjadi tantangan, misalnya; bagaimana Anda mengembalikan kelas dasar dari panggilan fungsi?

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

Atau saat mengetik?

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

Jadi, saya mencoba menghindarinya ketika saya bisa, dan menggunakannya ketika saya harus. Jika Anda harus, saya akan menyarankan agar Anda mengikuti pola ini:

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

Sekarang Anda dapat (lebih) dengan mudah bekerja dengan BaseClass. Namun, ada kalanya, seperti situasi saya saat ini, di mana mengekspos kelas turunan, dari dalam kelas dasar, tidak diperlukan dan menggunakan saran @ M-motif mungkin adalah pendekatan yang tepat.

Namun, menggunakan kode @ M-motif hanya berfungsi selama kelas dasar tidak berisi konstruktor instance dalam tumpukan panggilan. Sayangnya kelas dasar saya menggunakan konstruktor contoh.

Oleh karena itu, inilah metode ekstensi saya yang memperhitungkan konstruktor 'contoh' kelas dasar:

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