.NET:静的メソッドで「this」クラスのタイプを決定します


94

非静的メソッドで私は使用できthis.GetType()、それはを返しますTypeType静的メソッドでどうすれば同じことができますか?もちろん、私はランタイムでのみ知られているtypeof(ThisTypeName)ので、単に書くことThisTypeNameはできません。ありがとう!


16
あなたは静的なコンテキストにいて、typeof(ThisTypeName)を書き込むことができませんか?どうやって?
Bruno Reis、

1
静的メソッドの内部には「ランタイム」のようなものはありません(静的メソッドに渡される引数について話していないと仮定します)。その場合、単純にtypeof(RelevantType)と言うことができます。
Manish Basantani、2010年

2
静的メソッドを仮想にすることはできません。あなたはすでにタイプを知っています。
Hans Passant

6
抽象クラスから多くの派生クラスがあります。基本抽象クラスには、静的辞書<Int、Type>があります。そのため、派生クラスは静的コンストラクター(dic.Add(N、T))にそれ自体を「登録」します。そして、はい、私はタイプを知っています:)私は少し怠惰で、テキストを置き換えるのが好きではなく、実行時に「T」を決定できるかどうか疑問に思っていました。質問を単純化するためだけに必要だったので、私の嘘を許してください。そしてそれは働きました;)今受け入れられた解決策があります。ありがとう。
Yegor

サブクラスはスーパークラスの静的メソッドを継承しますか?スーパークラスの静的メソッドがそのすべてのサブクラスに役立つことは意味がないのでしょうか。静的とは単にインスタンスがないことを意味します。確かに、共通の基本クラスの共通コードの原則は、静的メソッドとインスタンスメソッドに適用されますか?
Matt Connolly、

回答:


134

this.GetType()静的メソッドと同等の1ライナーを探している場合は、以下を試してください。

Type t = MethodBase.GetCurrentMethod().DeclaringType

ただし、これは単にを使用するよりもはるかに高価ですtypeof(TheTypeName)


1
これは正常に動作します。ありがとう:)それはかなりまれに呼ばれることになるので、それほど高価ではありません。
Yegor

2
反対に、「高価な」とは、Jaredはプロセッサにコストがかかることを意味し、通常は低速です。しかし彼は、「はるかに高価である」という意味で遅いと述べた。ロケットガイダンスシステムを設計している場合を除いて、おそらくまったく遅くなりません。
Dan Rosenstark、2010年

1
GetCurrentMethodがいくつかの深刻なパフォーマンスの問題を引き起こすのを見てきました。ただし、型を取得しているだけなので、キャッシュできます。
ジョナサンアレン2010年

51
これは常に、サブクラスの場合に呼び出されたクラスではなく、現在のメソッドを実装するクラスを返します。
Matt Connolly

3
コードが別のクラス名などに移行された場合にエラーを回避するのは便利だと思いますが、typeof(TheTypeName)とにかく優れたリファクタリングツールで対処する必要があります。
Nyerguds、2015

59

他の回答ではまだ明確にされていないものがあります。これは、実行時にのみ利用できるタイプの考えに関連しています。

派生型を使用して静的メンバーを実行する場合、バイナリでは実際の型名は省略されます。たとえば、次のコードをコンパイルします。

UnicodeEncoding.GetEncoding(0);

ここでildasmを使用します...呼び出しが次のように発行されることがわかります。

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

コンパイラが呼び出しを解決しましたEncoding.GetEncoding-残っている痕跡はありませんUnicodeEncoding。それはあなたの「現在のタイプ」の考えを無意味なものにします、私は恐れています。


24

別の解決策は、自己参照型を使用することです

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

これで、Parent内の呼び出しタイプtypeof(TSelfReferenceType)は、インスタンスを必要とせずに、呼び出し元のTypeを取得して返します。

Child.GetType();

-ロブ


私はこれをシングルトンパターンに使用しました。つまり、Singleton <T> ...静的メンバーは、エラーメッセージまたは必要な場所でtypeof(T)を参照できます。
ヨーヨー

1
こんにちは。静的な基本関数から子の型を見つけるための回避策を提供するので、私はこの答えを本当に気に入って感謝しています。
ビルソフトウェアエンジニア

1
良いですね。残念ながら、C#では、この小さなコードの複製なしではこれを行うことはできません。
表示名


6

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

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

ここに明らかなものが欠けていますか?


7
Fooから派生したクラスBarを作成し、そのクラスがMethod1を継承する場合、これは機能しません。Bar.Method1の呼び出しは、typeof(Foo)を処理しますが、これは間違っています。継承されたMethod1は、何らかの方法でそれがBarで生成されていることを認識し、typeof(Bar)を取得する必要があります。
JustAMartin 2013年

0

メンバーが静的である場合、実行時にそのメンバーがどの型に属しているかが常にわかります。この場合:

class A
{
  public static int GetInt(){}

}
class B : A {}

呼び出すことはできません(編集:どうやら、以下のコメントを見ることができますが、それでもAを呼び出すことになります)。

B.GetInt();

メンバーは静的であるため、継承シナリオには関与しません。エルゴ、あなたはいつもタイプがAであることを知っています。


4
B.GetInt()呼び出すことができます-少なくともプライベートでない場合は可能ですが、コンパイルはそれをA.GetInt()の呼び出しに変換します。それを試してみてください!
Jon Skeet

Jonのコメントに関する注意:C#のデフォルトの可視性は非公開であるため、この例は機能しません。
Dan Rosenstark、2010年

0

私の目的では、@ 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

編集 この方法は、markmnlが指摘したように、実行可能ファイル/ライブラリを含むPDBファイルを展開する場合にのみ機能します。

それ以外の場合は、検出すべき大きな問題になります。開発ではうまく機能しますが、本番環境では機能しない可能性があります。


ユーティリティメソッド。コードのすべての場所から、必要なときにメソッドを呼び出すだけです。

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

1
StackTraceは、デバッグビルドでのみ使用できます
markmnl '12 / 12/16

不正解:.pdbファイルをリリースモードでもデプロイすると、StackTraceが利用可能になります。stackoverflow.com/questions/2345957/...
T-moty

私はあなたの要点を得ました。PDBファイルがデプロイされている場合にのみメソッドが機能することは許容されません。私は答えを編集します
T-moty
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.