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

时间:2012-06-22 19:11:25

标签: c# properties instance

是否可以在不创建实例的情况下获取价值?

我有这堂课:

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

    public MyClass()
    {
    }
}

现在我需要获取值“David”,而不创建MyClass的实例。

8 个答案:

答案 0 :(得分:92)

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

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

面颊但仍然正确答案

  

是否可以在不创建实例的情况下获取价值?

是的,但只能通过一些非常可怕的代码,使用DynamicMethod创建null this // 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

请不要这样做。 曾经。这是可怕的。它应该被践踏,切成小块,着火,然后再次切断。虽然有趣,不是吗? ;)

这是有效的,因为它使用的是callvirt而不是this。通常,C#编译器会使用var method = typeof(MyClass).GetProperty("Name").GetGetMethod(); var openDelegate = (Func<MyClass, string>) Delegate.CreateDelegate (typeof(Func<MyClass, string>), method); Console.WriteLine(openDelegate(null)); 调用,即使它没有调用虚拟成员,因为它会“免费”获取空引用(就IL流而言)。像这样的非虚拟调用首先不会检查是否为null,它只是调用该成员。如果您在属性调用中选中了{{1}},则会发现它为空。

编辑:正如Chris Sinclair所说,你可以更简单地使用一个开放的委托实例:

{{1}}

(但请不要!)

答案 1 :(得分:62)

您可以将该属性设为 static

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

用法:

MyClass.Name;

答案 2 :(得分:4)

您可以按照许多其他人的指示制作您的财产static

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

请注意,这意味着您的MyClass实例将不再具有自己的Name属性,因为静态成员属于该类,而不属于它的单个对象实例。

修改 在一个注释中,您提到要覆盖子类中的Name属性。同时,您希望能够在类级别访问它(无需创建类的实例即可访问它)。

对于静态属性,您只需在每个类中创建一个新的Name属性。由于它们是static,因此您总是(几乎总是,yay反射)将使用特定类访问它们,因此您将指定要获取的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"
}

作为旁注,由于您声明的属性只有一个getter并且它返回一个常量值,我建议您改为使用const或静态readonly变量。

<击>
public const string Name = "David";
public static readonly string Name = "David";

两者的用法都是一样的:

string name = MyClass.Name;

const的主要好处(和缺点)是,在编译代码时,对它的所有引用实际上都被其值替换。这意味着它会更快一些,但是如果你改变它的值,你将需要重新编译引用它的所有代码。

答案 3 :(得分:3)

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

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

答案 4 :(得分:2)

每当您编写C#代码时,请始终检查您的方法和属性getter / setter代码是否与该类的其他实例成员一起任何。如果他们不这样做,请务必应用 static 关键字。当然这里的情况,它很容易解决你的问题。

我真正发布这个问题的原因是在某些答案中有一些语言偏见。您无法在空对象上调用实例方法的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;
}

答案 5 :(得分:1)

创建一个静态属性:

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

    public MyClass()
    {
    }
}

得到它:

string name1 = MyClass.Name;

答案 6 :(得分:0)

创建静态类或静态属性,您不必显式实例化它。

答案 7 :(得分:0)

这是不可能的。由于Name是一个实例属性,因此如果您有实例,则只能获取其值。

另请注意,您不是在讨论参数,而是关于属性