2010-04-20 54 views
47

我的搜索一直在打开解释如何使用和应用属性到课程的指南。我想学习如何创建自己的属性类以及它们如何工作的机制。属性类如何工作?

如何属性类实例化?当它们被应用到的类被实例化时,它们是否被实例化?是实例化每个类实例化,它被应用到?例如。如果我将SerializableAttribute类应用于MyData类,并且实例化5个MyData实例,那么会在幕后创建5个SerializbleAttribute类的实例吗?或者在它们之间只有一个实例共享?

如何属性类的实例访问它们所关联的类? SerializableAttribute类如何访问它所应用的类,以便它可以序列化它的数据?它是否有某种SerializableAttribute.ThisIsTheInstanceIAmAppliedTo属性? :)或者它在相反的方向工作,每当我序列化的东西,Serialize函数我传递MyClass实例将反射性通过属性并找到SerialiableAttribute实例?

+4

+1大家有帮助的答案。现在我清楚地明白,属性本身不会有任何行为,也不会改变它们所应用的类的行为。它们只是额外的元数据固定到一个类。因此,我认为“行为”实际上不是属性类的代码,而是其他代码,如Serialize方法,解释元数据并使用它来有条件地执行操作(例如查看Serializable属性的Serialize方法)。 – AaronLS 2010-04-20 18:26:21

+0

查看属性构造函数何时运行的很好的示例:http://stackoverflow.com/a/1168590/84206 – AaronLS 2014-06-25 19:31:39

回答

32

我以前在日常工作中没有使用过属性,但我已经阅读过它们。 另外我做了一些测试,以备份我在这里要说的内容。如果我在任何地方都错了 - 随时告诉我这个:)

从我所知道的,属性并不像普通类一样。当你创建一个应用对象时,它们不会被实例化,而不是一个静态实例,而不是每个对象的实例。 他们也没有访问他们应用到的类。

相反,它们的作用类似于类的属性(属性?:P)。不像.NET类属性,更像是在“玻璃的一种属性是透明度”类属性中。您可以通过反射来检查哪些属性应用于某个类,然后对其进行相应处理。它们实质上是连接到类定义的元数据,而不是该类型的对象。

你可以尝试获取一个类,方法,属性等等的属性列表。当你得到这些属性的列表 - 这是他们将被实例化的地方。然后您可以对这些属性中的数据采取行动。

E.g. Linq表中,属性具有定义它们引用的表/列的属性。但是这些类不使用这些属性。相反,DataContext会在将linq表达式树转换为SQL代码时检查这些对象的属性。

现在对于一些真实的例子..我已经在LinqPad中跑过这些,所以不要担心奇怪的Dump()方法。我已经为Console.WriteLine取代它使代码更容易理解不知道是谁做这件事:)

void Main() 
{ 
    Console.WriteLine("before class constructor"); 
    var test = new TestClass(); 
    Console.WriteLine("after class constructor"); 

    var attrs = Attribute.GetCustomAttributes(test.GetType()).Dump(); 
    foreach(var attr in attrs) 
     if (attr is TestClassAttribute) 
      Console.WriteLine(attr.ToString()); 
} 

public class TestClassAttribute : Attribute 
{ 
    public TestClassAttribute() 
    { 
     DefaultDescription = "hello"; 
     Console.WriteLine("I am here. I'm the attribute constructor!"); 
    } 
    public String CustomDescription {get;set;} 
    public String DefaultDescription{get;set;} 

    public override String ToString() 
    { 
     return String.Format("Custom: {0}; Default: {1}", CustomDescription, DefaultDescription); 
    } 
} 

[Serializable] 
[TestClass(CustomDescription="custm")] 
public class TestClass 
{ 
    public int Foo {get;set;} 
} 

这种方法的控制台结果是人们:

before class constructor 
after class constructor 
I am here. I'm the attribute constructor! 
Custom: custm; Default: hello 

Attribute.GetCustomAttributes(test.GetType())返回此阵: (该表显示所有可用的列所有条目。所以,不,Serializable属性不具备这些属性:)) LinqPad Attributes Array

得到任何MOR问题?随意问!

UPD: 我见过你问一个问题:为什么使用它们?作为一个例子,我会告诉你关于XML-RPC.NET库。 您将创建您的XML-RPC服务类,并使用代表xml-rpc方法的方法。现在最主要的是:在XmlRpc中,方法名可以有一些特殊字符,如点。所以,你可以有一个flexlabs.ProcessTask()xml rpc方法。同时仍然使用公用名称,因为它必须是

[XmlRpcMethod("flexlabs.ProcessTask")] 
public int ProcessTask_MyCustomName_BecauseILikeIt(); 

这让我的名字在我喜欢的方式方法,:

你会这样定义这个类。

+0

非常好的答案。 – Dhananjay 2014-05-14 02:50:34

6

是他们实例化,你给它的参数。

属性没有“访问”之类的。该属性附加到反射数据中类的/属性的属性列表中。

[Serializable] 
public class MyFancyClass 
{ ... } 

// Somewhere Else: 

public void function() 
{ 
    Type t = typeof(MyFancyClass); 
    var attributes = t.GetCustomAttributes(true); 

    if (attributes.Count(p => p is SerializableAttribute) > 0) 
    { 
     // This class is serializable, let's do something with it! 

    }  
} 
+1

我问这不难,但为了提高我的理解:如果它属性的好处是什么只是作为一面旗帜?其他设计可以做到这一点,就像MyFancyClass实现了IsSerialiable接口或者具有IsSerializable属性的接口一样。 Wh是一个属性吗? SerializableAttribute类本身,该属性类本身中的代码以及该类中的数据/属性填充了什么样的作用? – AaronLS 2010-04-20 16:21:13

+1

@AaronLS您可以在运行时添加属性。即使代码不知道如何处理它们,也可以在读取/写入文件中的对象时保留它们。 – phkahler 2010-04-20 18:07:34

1

没有多少时间给你一个更全面的答案,但是你可以找到已经应用到一个值使用反射的属性。至于创建它们,您从属性类继承并从那里开始工作 - 并且您提供的属性值将传递给Attribute类的构造函数。

它已经有一段时间,你可能可以告诉...

马丁

16

属性是可以连接到各个部分的代码基本上元数据。然后这个元数据可以被interogate并影响某些操作的行为。

属性可以应用到你的代码的几乎每一个方面。例如,可以在Assembly级别关联属性,如AssemblyVersion和AssemblyFileVersion属性,这些属性管理与程序集关联的版本号。

[assembly: AssemblyVersion("1.0.0.0")] 
[assembly: AssemblyFileVersion("1.0.0.0")] 

然后,Serializable属性例如可以应用于类型声明来将该类型标记为支持序列化。实际上,这个属性在CLR中有特殊的含义,实际上作为一个特殊的指令直接存储在IL中的类型中,这被优化为存储为一个比特标志,可以更有效地处理,有几个属性这种性质被称为伪定制属性。

还有其他属性可以应用于方法,属性,字段,枚举,返回值等。您可以通过查看这个链接 http://msdn.microsoft.com/en-us/library/system.attributetargets(VS.90).aspx

得到进一步的属性可以被应用到可能的目标的想法为此,您可以定义自己的自定义属性,然后将其应用于您的属性适用的适用目标。然后在运行时,您的代码可以反映自定义属性中包含的值并采取适当的操作。

对于一个相当天真的例子,这仅仅是为了举例:) 您可能想要编写一个持久性引擎,它会自动将Classes映射到数据库中的表,并将Class的属性映射到表列。你可以先从定义两个自定义属性

TableMappingAttribute 
ColumnMappingAttribute 

然后你就可以应用到你的类,作为一个例子,我们有一个Person类

[TableMapping("People")] 
public class Person 
{ 
    [ColumnMapping("fname")] 
    public string FirstName {get; set;} 

    [ColumnMapping("lname")] 
    public string LastName {get; set;} 
} 

当这编译,除了一个事实,即编译器发出由自定义属性定义的额外元数据,其他影响不大。但是,现在您可以编写一个PersistanceManager,它可以动态检查Person类实例的属性并将数据插入到People表中,将FirstName属性中的数据映射到fname列,将LastName属性映射到lname列。

至于你关于属性实例的问题,属性的实例并不是为你的类的每个实例创建的。 People的所有实例将共享TableMappingAttribute和ColumnMappingAttributes的同一个实例。实际上,属性实例只有在您第一次真正查询属性时才会创建。

+0

@Chris +1我曾经认为序列化使用的属性和ORM的例子在编译时做了一些非常神奇的事情来分析对象,以便稍后在运行时知道如何读/写对象来自二进制/ xml文件(序列化)或数据库(ORM)。我想也许这些属性有一些“运行在编译时代码”。所以很长一段时间我想知道我能用属性做些什么很酷的事情。经过研究后,我意识到自己的看法与事实很不相称,但从未完全弄清楚属性如何提供习惯的“行为”。 – AaronLS 2010-04-20 18:33:00

6

认为属性是附属于类或方法定义(嵌入在程序集元数据中)的post-its。

然后,您可以拥有一个处理器/运行器/检查器模块,通过反射接受这些类型,查找这些帖子并以不同方式处理它们。这被称为声明式编程。你声明了一些行为,而不是在类型中为它们编写代码。

  • 类型上的可序列化属性声明它是构建为序列化的。然后XmlSerializer可以接受这个类的一个对象并执行必要的操作。您需要使用正确的post-its标记需要序列化/隐藏的方法。
  • 另一个例子是NUnit。 NUnit运行器查看目标程序集中定义的所有类的[TestFixture]属性以标识测试类。然后,它查找标有[Test]属性的方法来标识测试,然后运行测试并显示结果。

您可能需要运行this tutorial at MSDN,其中大部分问题都会在最后回答一个示例。虽然他们可能已经提取了一种称为 Audit(Type anyType);的方法,而不是重复该代码。该示例通过检查属性来“打印信息”,但您可以以同样的方式做任何事情。

2

如果你仔细看看这个可下载的开源代码LINQ to Active Directory (CodePlex),你可能会发现Attributes.cs文件的机制,Bart De Smet已经写了他所有的属性类定义。我在那里学到了属性。

总之,您可以专门研究Attribute类,并根据您的需求编写一些专用属性。

public class MyOwnAttributeClass : Attribute { 
    public MyOwnAttributeClass() { 
    } 
    public MyOwnAttributeClass(string myName) { 
     MyName = myName; 
    } 
    public string MyName { get; set; } 
} 

然后,您可以在MyOwnAttributeClass变得有用的任何地方使用它。它可能是通过类定义或属性定义。

[MyOwnAttributeClass("MyCustomerName")] 
public class Customer { 
    [MyOwnAttributeClass("MyCustomerNameProperty")] 
    public string CustomerName { get; set; } 
} 

然后,您可以像这样把它通过反射:

Attribute[] attributes = typeof(Customer).GetCustomAttribute(typeof(MyOwnAttributeClass)); 

考虑您方括号把属性永远是你的属性的构造函数。所以,如果你想拥有一个参数化属性,你需要为你的构造函数编码。

此代码按原样提供,可能无法编译。它的目的是让你知道它是如何工作的。

实际上,您通常希望为某个类使用不同的属性类。

希望这会有所帮助!