インスタンスを作成せずに値を取得することは可能ですか?
私はこのクラスを持っています:
public class MyClass
{
public string Name{ get{ return "David"; } }
public MyClass()
{
}
}
ここで、MyClass のインスタンスを作成せずに、値「David」を取得する必要があります。
インスタンスを作成せずに値を取得することは可能ですか?
私はこのクラスを持っています:
public class MyClass
{
public string Name{ get{ return "David"; } }
public MyClass()
{
}
}
ここで、MyClass のインスタンスを作成せずに、値「David」を取得する必要があります。
本当の答え:いいえ。これはインスタンスプロパティであるため、インスタンスでのみ呼び出すことができます。インスタンスを作成するか、他の回答に示されているようにプロパティを静的にする必要があります。
静的メンバーとインスタンス メンバーの違いの詳細については、MSDNを参照してください。
冗談ですが、それでも正しい答え:
インスタンスを作成せずに値を取得することは可能ですか?
はい、null
ただしthis
、DynamicMethod
. サンプルコード:
// 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
呼び出しを使用します。これは、(IL ストリームに関する限り) "無料" で null 参照チェックを取得するためです。このような非仮想呼び出しは、最初に null かどうかをチェックせず、メンバーを呼び出すだけです。プロパティ呼び出し内で確認すると、null であることがわかります。this
編集: 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));
(でも、やめてください!)
そのプロパティを静的にすることができます
public static string Name{ get{ return "David"; } }
使用法:
MyClass.Name;
あなたの要件は奇妙に思えますが、ある種のメタデータを探していると思います。これを実現するために属性を使用できます。
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>());
他の多くの人が指摘しているように、プロパティを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
、コードがコンパイルされるときに、それへのすべての参照が実際にその値に置き換えられることです。つまり、少し高速になりますが、値を変更した場合は、それを参照するすべてのコードを再コンパイルする必要があります。
C# コードを記述するときは常に、メソッドとプロパティの getter/setter コードがクラスの他のインスタンス メンバーに対して何らかの処理を行うかどうかを常に確認してください。そうでない場合は、必ずstaticキーワードを適用してください。確かにここでは、それはあなたの問題を自明に解決します。
私が実際にこの質問に投稿する理由は、一部の回答で言葉の偏りが少しあるためです。null オブジェクトでインスタンス メソッドを呼び出せないという C# の規則は、特定の C# 言語規則です。これは間違いなく非常に賢明な方法です。NullReferenceExceptions のトラブルシューティングに本当に役立ちます。この参照が nullであることを診断するのが非常に困難なメソッド内のどこかではなく、呼び出しサイトで発生します。
しかし、これは確かに 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;
}
静的プロパティを作成します。
public class MyClass
{
public static string Name { get { return "David"; } }
public MyClass()
{
}
}
そのようにそれを取得します:
string name1 = MyClass.Name;
静的クラスまたは静的プロパティを作成します。明示的にインスタンス化する必要はありません。
それは不可能です。インスタンスプロパティと同様Name
に、インスタンスがある場合にのみその値を取得できます。
また、パラメータについてではなく、プロパティについて話していることに注意してください。