web-dev-qa-db-ja.com

C#インスタンスを作成せずにプロパティ値を取得しますか?

インスタンスを作成せずに値を取得することは可能ですか?

私はこのクラスを持っています:

public class MyClass
{
    public string Name{ get{ return "David"; } }

    public MyClass()
    {
    }
}

ここで、MyClassのインスタンスを作成せずに、値「David」を取得する必要があります。

34
user1475694

本当の答え:いいえ。これはinstanceプロパティであるため、インスタンスでのみ呼び出すことができます。インスタンスを作成するか、他の回答に示されているようにプロパティを静的にする必要があります。

静的メンバーとインスタンスメンバーの違いの詳細については、 [〜#〜] msdn [〜#〜] を参照してください。

ほっぺたの舌ですが、それでも正解です

インスタンスを作成せずに値を取得することは可能ですか?

はい。ただし、 null を使用して、thisDynamicMethod(プロパティでは使用しません)として渡すILを作成する非常に恐ろしいコードを介してのみです。サンプルコード:

// Jon Skeet explicitly disclaims any association with this horrible code.
// THIS CODE IS FOR FUN ONLY. USING IT WILL INCUR WAILING AND GNASHING OF TEETH.
using System;
using System.Reflection.Emit;

public class MyClass
{
    public string Name { get{ return "David"; } }
}


class Test    
{
    static void Main()
    {
        var method = typeof(MyClass).GetProperty("Name").GetGetMethod();
        var dynamicMethod = new DynamicMethod("Ugly", typeof(string), 
                                              Type.EmptyTypes);
        var generator = dynamicMethod.GetILGenerator();
        generator.Emit(OpCodes.Ldnull);
        generator.Emit(OpCodes.Call, method);
        generator.Emit(OpCodes.Ret);
        var ugly = (Func<string>) dynamicMethod.CreateDelegate(
                       typeof(Func<string>));
        Console.WriteLine(ugly());
    }
}

これをしないでください。 これまで。それは恐ろしいです。それは踏みつけられ、少しに切り刻まれ、火をつけられ、そして再び切り刻まれるべきです。楽しいですよね? ;)

これは、callの代わりにcallvirtを使用しているために機能します。通常、C#コンパイラはcallvirt呼び出しを使用します仮想メンバーを呼び出していない場合でも「無料で」null参照チェックを取得するため(ILストリームに関する限り)。このような非仮想呼び出ししない最初にnullをチェックし、メンバーを呼び出すだけです。プロパティ呼び出し内でthisをチェックした場合、それはnullであることがわかります。

編集:Chris Sinclairが指摘したように、オープンデリゲートインスタンスを使用すると、より簡単に実行できます。

var method = typeof(MyClass).GetProperty("Name").GetGetMethod();
var openDelegate = (Func<MyClass, string>) Delegate.CreateDelegate
    (typeof(Func<MyClass, string>), method);
Console.WriteLine(openDelegate(null));

(しかし、繰り返しますが、しないでください!)

93
Jon Skeet

あなたはそのプロパティを作ることができます静的

public static string Name{ get{ return "David"; } } 

使用法:

MyClass.Name;
62
alexm

他の多くの人が指摘しているように、プロパティを static にすることができます。

public static string Name{ get{ return "David"; } }

静的メンバーはクラスの個々のオブジェクトインスタンスではなくクラスに属しているため、これはMyClassのインスタンスが独自のNameプロパティを持たなくなることを意味することに注意してください。

編集:メモで、サブクラスのNameプロパティをオーバーライドすると述べました。同時に、クラスレベルでアクセスできるようにする必要があります(クラスのインスタンスを作成せずにアクセスできます)。

静的プロパティの場合、各クラスに新しいNameプロパティを作成するだけです。それらはstaticであるため、常に(ほとんどの場合、リフレクション)特定のクラスを使用してアクセスすることになります。したがって、取得するNameのバージョンを指定することになります。そこでポリモーフィズムをハックして、MyClassの特定のサブクラスから名前を取得したい場合は、リフレクションを使用して行うことができますが、そうすることはお勧めしません。

コメントの例を使用して:

public class Dad 
{ 
    public static string Name { get { return "George"; }
}

public class Son : Dad
{
    public static string Name { get{ return "Frank"; }
}

public static void Test()
{
    Console.WriteLine(Dad.Name); // prints "George"
    Console.WriteLine(Son.Name); // prints "Frank"
    Dad actuallyASon = new Son();
    PropertyInfo nameProp = actuallyASon.GetType().GetProperty("Name");
    Console.WriteLine(nameProp.GetValue(actuallyASon, null)); // prints "Frank"
}

ちなみに、ゲッターのみを持つプロパティを宣言していて、定数値を返しているので、代わりに const またはstatic readonly 変数を使用することをお勧めします。

public const string Name = "David";
public static readonly string Name = "David";

両方の使用法は同じです:

string name = MyClass.Name;

constの主な利点(および欠点)は、コードのコンパイル時に、それへのすべての参照が実際にその値に置き換えられることです。つまり、少し速くなりますが、値を変更した場合は、それを参照するすべてのコードを再コンパイルする必要があります。

4
Jon Senchyna

要件は奇妙に思えますが、何らかのメタデータを探していると思います。これを実現するために属性を使用できます。

public class NameAttribute : Attribute {
  public string Name { get; private set; }
  public NameAttribute(string name) {
    Name = name;
  }
}

[Name("George")]
public class Dad { 
  public string Name { 
    get { 
      return NameGetter.For(this.GetType()); 
    }
  }
}

[Name("Frank")]
public class Son : Dad {
}

public static class NameGetter {
  public static string For<T>() {
    return For(typeof(T));
  }
  public static string For(Type type) {
    // add error checking ...
    return ((NameAttribute)type.GetCustomAttributes(typeof(NameAttribute), false)[0]).Name;
  }
}

これで、このコードはインスタンスの有無にかかわらず名前を取得できます。

Console.WriteLine(new Dad().Name);
Console.WriteLine(new Son().Name);
Console.WriteLine(NameGetter.For<Dad>());
Console.WriteLine(NameGetter.For<Son>());
3
Jordão

C#コードを作成するときは常に、メソッドとプロパティのゲッター/セッターコードがクラスの他のインスタンスメンバーでanythingを実行するかどうかを常に確認してください。そうでない場合は、必ずstaticキーワードを適用してください。確かにここの場合、それはあなたの問題を簡単に解決します。

私がこの質問に実際に投稿する理由は、いくつかの回答で言語バイアスが少し働いているからです。 nullオブジェクトでインスタンスメソッドを呼び出すことができないC#ルールは、特定のC#言語ルールです。これは間違いなく非常に賢明な方法です。NullReferenceExceptionsのトラブルシューティングに役立ちます。これらは、メソッド内のどこかではなく、呼び出しサイトで発生し、this参照がヌル。

ただし、これはCLRの要件でも、CLRで実行されるすべての言語の要件でもありません。実際、C#で一貫して強制されていなくても、拡張メソッドで簡単にバイパスできます。

public static class Extensions {
    public static bool IsNullOrEmpty(this string obj) {
        return obj != null && obj.Length > 0;
    }
}
...
        string s = null;
        bool empty = s.IsNullOrEmpty();    // Fine

また、同じルールを持たない言語からプロパティを使用しても問題なく機能します。 C++/CLIのように:

#include "stdafx.h"

using namespace System;
using namespace ClassLibrary1;    // Add reference

int main(array<System::String ^> ^args)
{
    MyClass^ obj = nullptr;
    String^ name = obj->Name;     // Fine
    Console::WriteLine(name);
    return 0;
}
2
Hans Passant

静的プロパティを作成します。

public class MyClass
{
    public static string Name { get { return "David"; } }

    public MyClass()
    {
    }
}

そのようにそれを取得します:

string name1 = MyClass.Name;
1
Dave New

静的クラスまたは静的プロパティを作成します。明示的にインスタンス化する必要はありません。

0

それは不可能です。 Nameはインスタンスプロパティであるため、インスタンスがある場合にのみその値を取得できます。

また、パラメータについてではなく、プロパティについて話していることに注意してください。

0
O. R. Mapper