DifferencesC #Two attributes in(PropertyAndAttribute)
14:19:21 | category: Technology | label: C # property attribut | large font size, medium/small subscription
difference between two attributes (property and attribute) in C #
in C #, there are two attributes: Property and attribute, both Chinese meanings include features and attributes, but their usage is different. For the sake of difference, this article calls property a feature and attribute a property.
property is relatively simple. It is commonly used get and set. It is mainly used to provide interfaces for reading and setting private and protected variables in the class. For more information about property, see Article :
http://blog.csdn.net/tjvictor/archive/2006/06/23/824617.aspx
attribute is the main character of this article, I think it is appropriate to call it an attribute. Attribute refers to a description of the characteristics of a thing attached to a thing. Attribute does this. It allows you to associate information with the C # type you define as a Type annotation. This information is arbitrary, that is, it is not determined by the language itself. You can establish and associate any type of information at will. You can define the design information and runtime information, or even the behavior characteristics of the runtime. The key lies in that this information can not only be extracted by users as a type of annotation, but can also be recognized by the compiler, as an auxiliary condition for compilation, You can compile the Program .
the following content and Code are derived from inside C # sencond edition.
define attributes:
an attribute is actually derived from system. class of the attribute base class. The system. Attribute Class contains several methods for accessing and checking custom attributes. Although you have the right to define any class as an attribute, it makes sense to use the system. Attribute derived class by convention. Example:
Public Enum reghives
{< br> hkey_classes_root,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
hkey_current_config
}
Public class regkeyattribute: attribute
{
Public regkeyattribute (reghives hive, string valuename)
{
This. Hive = hive;
This. valuename = valuename;
}
Protected reghives hive;
Public reghives hive
{
Get {return hive ;}
Set {hive = value ;}
}
Protected string valuename;
Public String valuename
{
Get {return valuename ;}
Set {valuename = value ;}
}
}
Here we have added enumeration of different registries, constructor of attribute classes, and two properties ). You can do a lot of things when defining attributes. Let's look at how to query attributes at runtime. To query the type or attributes attached to a member at runtime, reflection must be used. For more information, see my other simple article on reflection.
Http://blog.csdn.net/tjvictor/archive/2007/01/24/1492079.aspx
Query Class attributes:
Suppose you want to define a property that defines the remote server on which the object will be created. Without this attribute, you need to save this information in a constant or resource file of an application. To use properties, you only need to use the following method to mark the remote server name of the class:
Using system;
Namespace queryattribs
{
Public Enum remoteservers
{
Jeanvaljean,
Javert,
Cosette
}
Public class remoteobjectattribute: attribute
{
Public remoteobjectattribute (remoteservers server)
{
This. Server = server;
}
Protected remoteservers server;
Public String Server
{
Get
{
Return remoteservers. getname (
Typeof (remoteservers), this. Server );
}
}
}
[Remoteobject (remoteservers. Cosette)]
Class myremotableclass
{
}
Class Test
{
[Stathread]
Static void main (string [] ARGs)
{
Type type = typeof (myremotableclass );
Foreach (attribute ATTR in
Type. getcustomattributes (true ))
{
Remoteobjectattribute remoteattr =
ATTR as remoteobjectattribute;
If (null! = Remoteattr)
{
Console. writeline (
"Create this object on {0 }.",
Remoteattr. Server );
}
}
Console. Readline ();
}
}
}
The running result is:
Creat this object on Cosette.
Note: In this example, the attribute class name has an attribute suffix. However, when we attach this attribute to a type or member, the attribute suffix is not included. This is a simple method provided by the C # Language designer. When the compiler sees an attribute attached to a type or member, it searches for a system. Attribute derived class with the specified attribute name. If the compiler does not find a matching class, it adds attribute after the specified attribute name and then searches for it. Therefore, it is common to define an attribute class name as ending with an attribute and ignore this part of the name during use. The following code uses this naming method.
Query Method attributes:
In the following example, attributes are used to define a method as a transactional method. As long as the transactionableattribute attribute exists, the code knows that a method with this attribute can belong to a transaction.
Using system;
Using system. reflection;
Namespace methodattribs
{
Public class transactionableattribute: attribute
{
Public transactionableattribute ()
{
}
}
Class someclass
{
[Transactionable]
Public void Foo ()
{}
Public void bar ()
{}
[Transactionable]
Public void goo ()
{}
}
Class Test
{
[Stathread]
Static void main (string [] ARGs)
{
Type type = type. GetType ("methodattribs. someclass ");
Foreach (methodinfo method in type. getmethods ())
{
Foreach (attribute ATTR in
Method. getcustomattributes (true ))
{
If (ATTR is transactionableattribute)
{
Console. writeline (
"{0} is transactionable .",
Method. Name );
}
}
}
Console. Readline ();
}
}
}
The running result is as follows:
Foo is transactionable.
Goo is transactionable.
Query field attributes:
Assume that a class contains some fields and we want to save their values to the Registry. To this end, you can use the constructor with enumerated values and strings as parameters to define an attribute. This enumerated value represents the correct registry hive, and the string represents the registry value name. You can query the registry key of a field at runtime.
Using system;
Using system. reflection;
Namespace fieldattribs
{
Public Enum reghives
{
Hkey_classes_root,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
Hkey_current_config
}
Public class regkeyattribute: attribute
{
Public regkeyattribute (reghives hive, string valuename)
{
This. Hive = hive;
This. valuename = valuename;
}
Protected reghives hive;
Public reghives hive
{
Get {return hive ;}
Set {hive = value ;}
}
Protected string valuename;
Public String valuename
{
Get {return valuename ;}
Set {valuename = value ;}
}
}
Class someclass
{
[Regkey (reghives. HKEY_CURRENT_USER, "foo")]
Public int Foo;
Public int bar;
}
Class Test
{
[Stathread]
Static void main (string [] ARGs)
{
Type type = type. GetType ("fieldattribs. someclass ");
Foreach (fieldinfo field in type. getfields ())
{
Foreach (attribute ATTR in
Field. getcustomattributes (true ))
{
Regkeyattribute RKA =
ATTR as regkeyattribute;
If (null! = RKA)
{
Console. writeline (
"{0} will be saved in"
+ "{1 }\\\\{ 2 }",
Field. Name,
RKA. hive,
RKA. valuename );
}
}
}
Console. Readline ();
}
}
}
The running result is:
Foo will be saved in HKEY_CURRENT_USER \ foo
As you can see, attributes can be used to label classes, methods, and fields. They can attach user-defined information to entities and dynamically query data at runtime. Below I will talk about some default predefined attributes in C #, as shown in the following table:
Predefined attributes |
Effective Target |
Description |
Attributeusage |
Class |
Specify the valid usage of another attribute class |
Clscompliant |
All |
Indicates whether the program element is compatible with Cls. |
Conditional |
Method |
Indicates that if no associated string is defined, the compiler can ignore any call to this method. |
Dllimport |
Method |
Specifies the DLL location that contains the implementation of external Methods |
Stathread |
Method (main) |
Indicates that the default thread model of the program is Sta. |
Mtathread |
Method (main) |
Specifies that the default program model is multi-thread (MTA) |
Obsolete |
Besides assembly, module, parameter, and return |
Mark an element as unavailable, notifying users that this element will be used by future products |
Paramarray |
Parameter |
Allows a single parameter to be treated implicitly as a Params (array) parameter |
Serializable |
Class, struct, Enum, delegate |
All public and private fields of this type can be serialized. |
Nonserialized |
Field |
Applies to Fields marked as serializable classes, indicating that these fields cannot be serialized |
Structlayout |
Class, struct |
Specifies the nature of the data layout of a class or structure, such as auto, explicit, or sequential |
Threadstatic |
Field (static) |
Implement local thread storage (TLS ). A given static field cannot be shared across multiple threads. Each thread has a copy of this static field. |
The following describes several common attributes.
1. [stathread] and [mtathread] attributes
Class class1
{
[Stathread]
Static void main (string [] ARGs)
{
}
}
Use the stathread attribute to specify the default thread model of the program as a single-thread model. Note that the thread model only affects applications that use com InterOP. Applying this attribute to programs that do not use com InterOP will not produce any effect.
2. attributeusage attributes
You can also use the attributeusage attribute to define how you use these attributes in addition to the custom attributes of the General C # type. The attributeusage attribute of a file record is called as follows:
[Attributeusage (validon, allowmutiple = allowmutiple, inherited = inherited)]
The validon parameter is of the attributetargets type. The enumerated value is defined as follows:
Public Enum attributetargets
{
Assembly = 0x0001,
Module = 0x0002,
Class = 0x0004,
Struct = 0x0008,
Enum = 0x0010,
Constructor = 0x0020,
Method = 0x0040,
Property = 0x0080,
Field = 0x0100,
Event = 0x200,
Interface = 0x400,
Parameter = 0x800,
Delegate = 0x1000,
All = Assembly | module | class | struct | Enum | constructor | method | property | filed | event | interface | parameter | deleagte,
Classmembers = | class | struct | Enum | constructor | method | property | FIELD | event | delegate | Interface
}
Allowmultiple determines how many times an attribute can be used on a single field. By default, all attributes are used at a time. Example:
[Attributeusage (attributetargets. All, allowmultiple = true)]
Public class somethingattribute: attribute
{
Public somethingattribute (string Str)
{
}
}
// If allowmultiple = false, an error is returned.
[Something ("ABC")]
[Something ("def")]
Class myclass
{
}
The inherited parameter indicates whether the property can be inherited. The default value is false.
Inherited |
Allowmultiple |
Result |
True |
False |
The derived attribute overwrites the base attribute. |
True |
False |
The derived attributes and the base attributes coexist. |
Sample Code:
Using system;
Using system. reflection;
Namespace attribinheritance
{
[Attributeusage (
Attributetargets. All,
Allowmultiple = true,
// Allowmultiple = false,
Inherited = true
)]
Public class somethingattribute: attribute
{
Private string name;
Public string name
{
Get {return name ;}
Set {name = value ;}
}
Public somethingattribute (string Str)
{
This. Name = STR;
}
}
[Something ("ABC")]
Class myclass
{
}
[Something ("def")]
Class another: myclass
{
}
Class Test
{
[Stathread]
Static void main (string [] ARGs)
{
Type type =
Type. GetType ("attribinheritance. Another ");
Foreach (attribute ATTR in
Type. getcustomattributes (true ))
// Type. getcustomattributes (false ))
{
Somethingattribute SA =
ATTR as somethingattribute;
If (null! = SA)
{
Console. writeline (
"Custom attribute: {0 }",
SA. Name );
}
}
}
}
}
When allowmultiple is set to false, the result is:
Custom attribute: def
When allowmultiple is set to true, the result is:
Custom attribute: def
Custom attribute: ABC
NOTE: If false is passed to getcustomattributes, it will not search for the inheritance tree, so you can only get the derived class attributes.
3. Conditional attributes
You can attach this attribute to a method. In this way, when the compiler calls this method, if the corresponding string value is not defined, the compiler ignores this call. For example, whether the following method is compiled depends on whether the string "degug" is defined ":
[Condition ("debug")]
Public void somedebugfunc ()
{
Console. writeline ("somedebugfunc ");
}
Using system;
Using system. diagnostics;
Namespace condattrib
{
Class thing
{
Private string name;
Public thing (string name)
{
This. Name = Name;
# If debug
Somedebugfunc ();
# Else
Somefunc ();
# Endif
}
Public void somefunc ()
{Console. writeline ("somefunc ");}
[Conditional ("debug")]
[Conditional ("Andrew")]
Public void somedebugfunc ()
{Console. writeline ("somedebugfunc ");}
}
Public class class1
{
[Stathread]
Static void main (string [] ARGs)
{
Thing T = new thing ("T1 ");
}
}
}
4. Obsolete attributes
With the continuous development of code, you may not need to use some methods. You can delete all of them, but sometimes adding appropriate labels to them is more appropriate than deleting them, for example:
Using system;
Namespace obsattrib
{
Class someclass
{
[Obsolete ("Don't use oldfunc, use newfunc instead", true)]
Public void oldfunc () {console. writeline ("oops ");}
Public void newfunc () {console. writeline ("cool ");}
}
Class class1
{
[Stathread]
Static void main (string [] ARGs)
{
Someclass SC = new someclass ();
SC. newfunc ();
// SC. oldfunc (); // compiler Error
}
}
}
We set the second parameter of the obsolete attribute to true. When the function is called, the compiler will generate an error.
E: \ insidec # \ code \ chap06 \ obsattrib \ class1.cs (20): 'obsattrib. someclass. oldfunc () 'expired: 'don' t use oldfunc, use newfunc instead'
5. dllimport and structlayout attributes
Dllimport allows the C # code to call functions in the local code. The C # code calls them through the runtime function platform invoke.
If you want the runtime environment to correctly organize the structure from the managed code into unmanaged code (or vice versa), you need to add attributes to the schema declaration. In order for structure parameters to be correctly grouped, The structlayout attribute must be used to declare them, indicating that the data should be arranged strictly according to the format listed in the Declaration. If this is not done, data cannot be correctly grouped, and applications may encounter errors.
Using system;
Using system. runtime. interopservices; // For dllimport
Namespace nativedll
{
Public class test
{
// [Dllimport ("user32.dll")] // all the defaults are OK
[Dllimport ("USER32", entrypoint = "messageboxa ",
Setlasterror = true,
Charset = charset. ANSI, exactspelling = true,
Callingconvention = callingconvention. stdcall)]
Public static extern int messageboxa (
Int H, string M, string C, int type );
[Structlayout (layoutkind. Sequential)]
Public class systemtime {
Public ushort wyear;
Public ushort wmonth;
Public ushort wdayofweek;
Public ushort wday;
Public ushort whour;
Public ushort wminute;
Public ushort wsecond;
Public ushort wmilliseconds;
}
[Dllimport ("kernel32.dll")]
Public static extern void getlocaltime (systemtime st );
[Stathread]
Public static void main (string [] ARGs)
{
Messageboxa (0, "Hello World", "nativedll", 0 );
Systemtime ST = new systemtime ();
Getlocaltime (ST );
String S = string. Format ("Date: {0}-{1}-{2 }",
St. wmonth, st. wday, st. wyear );
String T = string. Format ("Time: {0 }:{ 1 }:{ 2 }",
St. whour, st. wminute, st. wsecond );
String u = S + "," + T;
Messageboxa (0, U, "now", 0 );
}
}
}
6. Accessory attributes
When. NET is used to generate any type of C # project, an assemblyinfo. CS is automatically generated.Source codeFile and application source code file. Assemblyinfo. CS contains the code in the accessory. Some of the information is purely information, while other information enables the runtime environment to ensure the unique name and version number for the Customer Code to reuse your accessories.
7. Context attributes
The. NET Cabinet also provides another attribute: context attribute. Context properties provide an intercept mechanism that can be processed before and after class instantiation and method calling. This function is used for remote object calls. It is used from the COM + component services and Microsoft Transaction Services (MTS) used by the com-based system ).