Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP_answers (1).docx
Скачиваний:
4
Добавлен:
01.03.2025
Размер:
2.9 Mб
Скачать

26. Понятие атрибутов в языке c#. Создание пользовательских атрибутов. Анализ атрибутов во время выполнения программы. Понятие рефлексии (reflection) в языке c#. Сериализация объектов.

Понятие атрибутов в языке C#

Types, members, and other entities in a C# program support modifiers that control certain aspects of their behavior. For example, the accessibility of a method is controlled using the public, protected, internal, and private modifiers. C# generalizes this capability such that user-defined types of declarative information can be attached to program entities and retrieved at run-time. Programs specify this additional declarative information by defining and using attributes.

The following example declares a HelpAttribute attribute that can be placed on program entities to provide links to their associated documentation.

using System;

public class HelpAttribute: Attribute { string url; string topic;

public HelpAttribute(string url) { this.url = url; }

public string Url { get { return url; } }

public string Topic { get { return topic; } set { topic = value; } } }

All attribute classes derive from the System.Attribute base class provided by the .NET Framework. Attributes can be applied by giving their name, along with any arguments, inside square brackets just before the associated declaration. If an attribute’s name ends in Attribute, that part of the name can be omitted when the attribute is referenced. For example, the HelpAttribute attribute can be used as follows.

[Help("http://msdn.microsoft.com/.../MyClass.htm")] public class Widget { [Help("http://msdn.microsoft.com/.../MyClass.htm", Topic = "Display")] public void Display(string text) {} }

This example attaches a HelpAttribute to the Widget class and another HelpAttribute to the Display method in the class. The public constructors of an attribute class control the information that must be provided when the attribute is attached to a program entity. Additional information can be provided by referencing public read-write properties of the attribute class (such as the reference to the Topic property previously).

Создание пользовательских атрибутов

A class that derives from the abstract class System.Attribute, whether directly or indirectly, is an attribute class. The declaration of an attribute class defines a new kind of attribute that can be placed on a declaration. By convention, attribute classes are named with a suffix of Attribute. Uses of an attribute may either include or omit this suffix.

The attribute AttributeUsage is used to describe how an attribute class can be used.

AttributeUsage has a positional parameter that enables an attribute class to specify the kinds of declarations on which it can be used. The example

using System;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)] public class SimpleAttribute: Attribute { ... }

defines an attribute class named SimpleAttribute that can be placed on class-declarations and interface-declarations only.

[Simple] class Class1 {...}

[SimpleAttribute] interface Interface1 {...}

AttributeUsage has a named parameter called AllowMultiple, which indicates whether the attribute can be specified more than once for a given entity. If AllowMultiple for an attribute class is true, then that attribute class is a multi-use attribute class, and can be specified more than once on an entity. If AllowMultiple for an attribute class is false or it is unspecified, then that attribute class is a single-use attribute class, and can be specified at most once on an entity.

using System;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class AuthorAttribute: Attribute { private string name;

public AuthorAttribute(string name) { this.name = name; }

public string Name { get { return name; } } }

defines a multi-use attribute class named AuthorAttribute. The example

[Author("Brian Kernighan"), Author("Dennis Ritchie")] class Class1 { ... }

shows a class declaration with two uses of the Author attribute.

AttributeUsage has another named parameter called Inherited, which indicates whether the attribute, when specified on a base class, is also inherited by classes that derive from that base class. If Inherited for an attribute class is true, then that attribute is inherited. If Inherited for an attribute class is false then that attribute is not inherited. If it is unspecified, its default value is true.

An attribute class X not having an AttributeUsage attribute attached to it, as in

using System;

class X: Attribute {...}

is equivalent to the following:

using System;

[AttributeUsage( AttributeTargets.All, AllowMultiple = false, Inherited = true) ] class X: Attribute {...}

Attribute classes can have positional parameters and named parameters. Each public instance constructor for an attribute class defines a valid sequence of positional parameters for that attribute class. Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class.

using System;

[AttributeUsage(AttributeTargets.Class)] public class HelpAttribute: Attribute { public HelpAttribute(string url) { // Positional parameter ... }

public string Topic { // Named parameter get {...} set {...} }

public string Url { get {...} } }

defines an attribute class named HelpAttribute that has one positional parameter, url, and one named parameter, Topic. Although it is non-static and public, the property Url does not define a named parameter, since it is not read-write.

This attribute class might be used as follows:

[Help("http://www.mycompany.com/.../Class1.htm")] class Class1 { ... }

[Help("http://www.mycompany.com/.../Misc.htm", Topic = "Class2")] class Class2 { ... }

An attribute consists of an attribute-name and an optional list of positional and named arguments. The positional arguments (if any) precede the named arguments. A positional argument consists of an attribute-argument-expression; a named argument consists of a name, followed by an equal sign, followed by an attribute-argument-expression, which, together, are constrained by the same rules as simple assignment. The order of named arguments is not significant.

In other contexts, inclusion of an attribute-target-specifier is permitted but unnecessary. For instance, a class declaration may either include or omit the specifier type:

[type: Author("Brian Kernighan")] class Class1 {}

[Author("Dennis Ritchie")] class Class2 {}

It is an error to specify an invalid attribute-target-specifier. For instance, the specifier param cannot be used on a class declaration:

[param: Author("Brian Kernighan")] // Error class Class1 {}

By convention, attribute classes are named with a suffix of Attribute. An attribute-name of the form type-name may either include or omit this suffix. If an attribute class is found both with and without this suffix, an ambiguity is present, and a compile-time error results. If the attribute-name is spelled such that its right-most identifier is a verbatim identifier, then only an attribute without a suffix is matched, thus enabling such an ambiguity to be resolved.

The example

using System;

[AttributeUsage(AttributeTargets.All)] public class X: Attribute {}

[AttributeUsage(AttributeTargets.All)] public class XAttribute: Attribute {}

[X] // Error: ambiguity class Class1 {}

[XAttribute] // Refers to XAttribute class Class2 {}

[@X] // Refers to X class Class3 {}

[@XAttribute] // Refers to XAttribute class Class4 {}

shows two attribute classes named X and XAttribute. The attribute [X] is ambiguous, since it could refer to either X or XAttribute. Using a verbatim identifier allows the exact intent to be specified in such rare cases. The attribute [XAttribute] is not ambiguous (although it would be if there was an attribute class named XAttributeAttribute!). If the declaration for class X is removed, then both attributes refer to the attribute class named XAttribute, as follows:

using System;

[AttributeUsage(AttributeTargets.All)] public class XAttribute: Attribute {}

[X] // Refers to XAttribute class Class1 {}

[XAttribute] // Refers to XAttribute class Class2 {}

[@X] // Error: no attribute named "X" class Class3 {}

It is a compile-time error to use a single-use attribute class more than once on the same entity.

An expression E is an attribute-argument-expression if all of the following statements are true:

The type of E is an attribute parameter type.

At compile-time, the value of E can be resolved to one of the following:

  • A constant value.

  • A System.Type object.

  • A one-dimensional array of attribute-argument-expressions.

For example:

using System;

[AttributeUsage(AttributeTargets.Class)] public class TestAttribute: Attribute { public int P1 { get {...} set {...} }

public Type P2 { get {...} set {...} }

public object P3 { get {...} set {...} } }

[Test(P1 = 1234, P3 = new int[] {1, 3, 5}, P2 = typeof(float))] class MyClass {}

Анализ атрибутов во время выполнения программы

An attribute instance is an instance that represents an attribute at run-time. An attribute is defined with an attribute class, positional arguments, and named arguments. An attribute instance is an instance of the attribute class that is initialized with the positional and named arguments.

Retrieval of an attribute instance involves both compile-time and run-time processing.

The compilation of an attribute with attribute class T, positional-argument-list P and named-argument-list N, consists of the following steps:

  1. Follow the compile-time processing steps for compiling an object-creation-expression of the form new T(P). These steps either result in a compile-time error, or determine an instance constructor C on T that can be invoked at run-time.

  2. If C does not have public accessibility, then a compile-time error occurs.

  3. For each named-argument Arg in N:

  • Let Name be the identifier of the named-argument Arg.

  • Name must identify a non-static read-write public field or property on T. If T has no such field or property, then a compile-time error occurs.

  1. Keep the following information for run-time instantiation of the attribute: the attribute class T, the instance constructor C on T, the positional-argument-list P and the named-argument-list N.

  2. Compilation of an attribute yields an attribute class T, an instance constructor C on T, a positional-argument-list P, and a named-argument-list N. Given this information, an attribute instance can be retrieved at run-time using the following steps:

  3. Follow the run-time processing steps for executing an object-creation-expression of the form new T(P), using the instance constructor C as determined at compile-time. These steps either result in an exception, or produce an instance O of T.

  1. For each named-argument Arg in N, in order:

  • Let Name be the identifier of the named-argument Arg. If Name does not identify a non-static public read-write field or property on O, then an exception is thrown.

  • Let Value be the result of evaluating the attribute-argument-expression of Arg.

  • If Name identifies a field on O, then set this field to Value.

  • Otherwise, Name identifies a property on O. Set this property to Value.

  • The result is O, an instance of the attribute class T that has been initialized with the positional-argument-list P and the named-argument-list N.

Indexers are implemented in .NET using indexed properties, and have a name in the .NET metadata. If no IndexerName attribute is present for an indexer, then the name Item is used by default. The IndexerName attribute enables a developer to override this default and specify a different name.

namespace System.Runtime.CompilerServices.CSharp { [AttributeUsage(AttributeTargets.Property)] public class IndexerNameAttribute: Attribute { public IndexerNameAttribute(string indexerName) {...}

public string Value { get {...} } } }

Понятие рефлексии (reflection) в языке C#

The following example shows how attribute information for a given program entity can be retrieved at run-time using reflection.

using System; using System.Reflection;

class Test { static void ShowHelp(MemberInfo member)

{ HelpAttribute a = Attribute.GetCustomAttribute(member, typeof(HelpAttribute)) as HelpAttribute; if (a == null) { Console.WriteLine("No help for {0}", member); } else { Console.WriteLine("Help for {0}:", member); Console.WriteLine(" Url={0}, Topic={1}", a.Url, a.Topic); } }

static void Main() { ShowHelp(typeof(Widget)); ShowHelp(typeof(Widget).GetMethod("Display")); } }

When a particular attribute is requested through reflection, the constructor for the attribute class is invoked with the information provided in the program source, and the resulting attribute instance is returned. If additional information was provided through properties, those properties are set to the given values before the attribute instance is returned.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]