C#获取属性值而不创建实例?

use*_*694 34 c# properties instance

是否有可能在不创建实例的情况下获得价值?

我有这门课:

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

    public MyClass()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我需要获取值"David",而不创建MyClass的实例.

Jon*_*eet 93

真实答案:没有.它是一个实例属性,因此您只能在实例上调用它.您应该创建一个实例,或者将该属性设置为静态,如其他答案所示.

有关静态成员和实例成员之间差异的更多信息,请参阅MSDN.

舌头但仍然正确答案:

是否有可能在不创建实例的情况下获得价值?

是的,但只能通过它创建一些IL传递一些非常可怕的代码nullthis(你不要在你的财产使用),使用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());
    }
}
Run Code Online (Sandbox Code Playgroud)

请不要这样做.永远.这太可怕了.它应该被践踏,切成小块,着火,然后再次切断.虽然有趣,不是吗?;)

这是有效的,因为它使用call而不是callvirt.通常,C#编译器会使用一个callvirt调用,即使它没有调用虚拟成员,因为它会"免费"获取空引用(就IL流而言).像这样的非虚拟调用首先检查无效,它只是调用成员.如果您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));
Run Code Online (Sandbox Code Playgroud)

(但是,请不要!)

  • @JonSkeet你可以使用这里指出的技术来避免IL生成吗?http://stackoverflow.com/questions/951624/how-to-create-a-delegate-to-an-instance-method-with-a-null-target编辑:嗯,也许不是.这是方法,而不是属性. (7认同)
  • 我不明白这一切,但我仍然感到印象深刻^^ (4认同)
  • @ChrisSinclair:很好 - 我把代码编辑成了答案. (2认同)

ale*_*exm 62

您可以将该属性设置为静态

public static string Name{ get{ return "David"; } } 
Run Code Online (Sandbox Code Playgroud)

用法:

MyClass.Name;
Run Code Online (Sandbox Code Playgroud)

  • +1因为我认为这个答案对OP的帮助比目前得分较高的徒劳无益. (17认同)
  • @michielvoo:嗯,你可以说我的答案的开头给出了*两个*选项 - 要么使属性静态,要么*创建一个实例.这个答案只给出了一个:)但是,是的,我没有举例说明如何*使属性保持静态,因为其他答案已经涵盖了这一点.我也相信给出答案的有用之处在于*除了OP以外的其他人*. (7认同)

Jor*_*dão 5

您的要求确实看起来很奇怪,但我认为您正在寻找某种元数据。您可以使用属性来实现此目的:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,此代码可以获取带实例和不带实例的名称:

Console.WriteLine(new Dad().Name);
Console.WriteLine(new Son().Name);
Console.WriteLine(NameGetter.For<Dad>());
Console.WriteLine(NameGetter.For<Son>());
Run Code Online (Sandbox Code Playgroud)