The brush of the artist may be different, but you can do without a brush. In C ++, types disappeared after the translation, but in C # they do not disappear and can be used at runtime. C # is Delphi stubborn on melkosofta and the main reason for the use of attributes with types is PropertyGrid, the former TValueListEditor. Well, then you can come to the not obvious conclusion that attributes with types are simple and convenient.
Previously, methods, fields, and class properties were purely interim between coders, one could say a method, or a function, or a field, or just a variable. But as soon as there is a type in memory, then it can be addressed, and when applying it is necessary to use exact terms. From any object you can get its type, and from the type you can get the names of the fields, properties and methods, and by the names you can get the value of the field - that is, another object, or call the method with all parameters and return value.
class X { class A { public int f1; public int p1 { get; set; } public int m1(string s, int i) { return (0); } } X() { A a = new A(); Type t = a.GetType(); FieldInfo fi = t.GetField("f1"); object of = fi.GetValue(a); PropertyInfo pi = t.GetProperty("p1"); MethodInfo mpi = pi.GetGetMethod(); object ompi = mpi.Invoke(a, null); MethodInfo mi = t.GetMethod("m1"); object om = mi.Invoke(a, new object[] { "param1", 2 }); } }
Thus, we got an alternative, complicated programming method, when we can write not the variables themselves, but their string names. String names can be changed.
Each object has two hypostases: on the one hand, it is a field of some kind, and on the other hand, it has its own type, in which there can be different fields. Types at runtime can not be changed, except to contact the address in the memory by the hacker method.
')
Each type has a list of attributes, this list may be empty, and may be full. This is where the fun begins. It turns out that each object has its own unique type. In other words, two variables of type int have two different types. These types may be the same, or they may be different, and they will differ in the list of attributes. It is clear that the exe-shnik is not overflowing with repeating types, the implementation goes through links, but in the leaky representation of the encoder level this is exactly the case.
class X { class ATTR1 : Attribute { public ATTR1() { } } class ATTR2 : Attribute { public ATTR2() { } } class A { [ATTR1] public int i1; [ATTR2] public int i2; } X() { object[] ai1 = a.GetType().GetField("i1").GetCustomAttributes(false); object[] ai2 = a.GetType().GetField("i2").GetCustomAttributes(false); } }
Objects have no attributes, only types have attributes. From each object we can get its type, and in the type to find the attributes. But since the type of each object is unique, we can say that the object has attributes. However, it can also be said that the object is described in some type, and in this type attributes are also assigned to this object. Thus, an object has two attribute lists — a list by its own type, and a list by type, in which this object is described.
class X { class ATTR1 : Attribute { public ATTR1() { } } class ATTR2 : Attribute { public ATTR2() { } } [ATTR1] public class A { } [ATTR2] public A a; X() { a = new A(); object[] inner = a.GetType().GetCustomAttributes(false); object[] outer = this.GetType().GetField("a").GetCustomAttributes(false); } }
Attributes have not only fields, but also methods and properties. To use their attributes first you need to find the object. When we look for the attributes of an object, we must select the appropriate list, and when we prescribe attributes, we must respectively write to the type that follows. Often, the encoder just in case checks the attributes both there and there, and if there is a conflict between the attributes, it gives priority to the field attribute over the type attribute.
Primitive coders believed that the main thing is to program the code. Then the ancestors came to the conclusion that the main thing is to structure the data. In our enlightened age, universal programs plow open spaces of a structured ocean of data, suggesting a new order there. One of these programs is PropertyGrid, which displays a data tree with the ability to change them. How to find public property - and immediately shows. And if a property is so non-standard that it can neither be viewed nor edited, then the PropertyGrid will look for an attribute with a description of the class with which you can view and fix the property. And if it does not find it, it will not show it. And che, the DBMS has long been keeping their data types and live happily ever after, why not keep the prog - there is nowhere to put the memory on the computers, and at speeds it is possible to code an uncontrollable piece.
Known glitches.
It works inside c #, but you should set it in OLE (COM, ActiveX), as some attributes are lost immediately, most likely when you switch from one c # dll to another. For example, when the glade itself (field) is described in one dll, and its type with the attribute is in the other, and the attribute will not disappear, its glades will disappear - it is also a class in turn. It is difficult to determine where exactly the glitch. Most likely CCW rolls in. CCW is such a magic word meaning a wrapper with a garbage collector for an unmanaged call. Sharpovs believe that the coders will write on Sharpe and occasionally pull up their old ideas on the pros, and the coders themselves believe that they will accompany their monsters by finishing the pieces on Sharpe.
As soon as the CCW can send in the garbage what should not be sent, then in the OLE version everything that is lost needs to be protected static. Those. for example, the sequence of properties in some type was lost, all properties are in place, but not so sorted. It means that, according to the logic of the program, it is necessary to go up and find where nothing is lost yet and create a static variable with a link to this object - they will not be sent to the garbage, they will be ashamed.
Hackers or not hackers?
The very concept of the reflection of pure water hacking, when we appeal to all closed members. The immutability of attributes at runtime, they de belong to the type, and the type cannot be changed - the same hacker problem as all reflection. Everything is changing. You just need to remember that by changing some kind of collection, you can ignore the fact that someone has already referred to it and built its data structure - something can fall off. For example, we change this the value of the Browsable attribute - God forbid this attribute is not explicitly stated in the source code. This attribute, if not present, is assigned to the type by default, but it cannot be changed if it is not explicitly stated - all Browsable attributes with all other properties will fall down. And it is extremely difficult to determine where the attribute was originally written at run time.
PropertyDescriptor pd = TypeDescriptor.GetProperties (_pi.DeclaringType) ["Name"];
BrowsableAttribute ba = (BrowsableAttribute) pd.Attributes [typeof (BrowsableAttribute)];
FieldInfo isBrowsable = ba.GetType (). GetField ("Browsable", BindingFlags.IgnoreCase | BindingFlags.NonPublic | BindingFlags.Instance);
isBrowsable.SetValue (ba, false);