1. What is C # reflection?
Reflection, which is translated into reflection in Chinese.
This is.. net ,. NET applications are composed of several parts: 'assembly ', 'module', and 'Type (class) '. Reflection provides a programming method, this allows programmers to obtain relevant information about these components during the running period, for example:
The Assembly class can obtain information about running accessories, dynamically load the accessories, find the type information in the accessories, and create instances of this type.
The type class can obtain the type information of an object. This information includes all elements of the object, such as methods, constructors, and attributes. The type class can obtain and call the information of these elements.
Methodinfo contains information about the method. You can use this class to obtain the name, parameter, and return value of the method and call it.
For example, fieldinfo and eventinfo are included in the system. Reflection namespace.
2. C # reflects the relationship between namespaces and accessories
Many people are not clear about this concept. For A. Net programmer, it is necessary to understand these concepts.
The namespace is similar to the Java package, but it is not exactly the same, because the Java package must be placed according to the directory location.. net. It only needs to add references.
What are accessories? In terms of words, just as it is said, before the ultimate .exe or. dll, irrelevant and related things (such as many classes) need to be packaged and assembled together. These things are called accessories. Of course, we can directly understand it as EXE and DLL.
The namespace of an assembly does not have a one-to-one relationship or mutual inclusion. An assembly can have multiple namespaces, and a namespace can also exist in multiple accessories. In this case, we may not understand it. Let's take an example:
- // Assembly:
- Namespace
N1
- {
Public
Class
AC1 {...}
Public
Class
Ac2 {...}
- }
- Namespace
N2
- {
Public
Class
AC3 {...}
Public
Class
Ac4 {...}
- }
- // Install accessory B:
- Namespace
N1
- {
Public
Class
BC1 {...}
Public
Class
BC2 {...}
- }
- Namespace
N2
- {
Public
Class
Bc3 {...}
Public
Class
Bc4 {...}
- }
Both of these accessories have namespaces N1 and N2, and each declares two classes. This is completely acceptable. Then we reference assembly a in an application, in this application, we can see that the classes in N1 are AC1 and ac2, And the classes in N2 are Ac3 and ac4.
If we remove the reference to a and then reference B to install the accessories, we can only see BC1, BC2, and bc3 and bc4 under N1 in this application.
Reference A and B at the same time, of course, you can see all the above classes.
Here, we can clearly understand a concept. The namespace only describes the type of a family, such as the Han nationality and Hui nationality; the installation of accessories indicates where a type exists.
An accessory is a type of place where it lives. To use a class in a program, you must tell the compiler where the class lives before the compiler can find it. That is to say, you must reference this assembly.
So when you write a program, you may not be sure where the class is, but you only know its name, can you use it? The answer is yes. This is reflection, that is, to provide this type of Address while the program is running, and find it.
3. What is the purpose of obtaining type information during runtime?
Some people may wonder why the code can be written during development and is still executed at runtime, which is not only tedious but also inefficient.
This is a matter of opinion, just like early binding and late binding. Some people are opposed to late binding on the grounds of waste efficiency, but many people do not realize that they have used late binding when enjoying the benefits of virtual functions. This question is open. It's not clear in just a few words, so it's just a few minutes.
In my opinion, late binding can bring a lot of convenience in design. Proper use can greatly improve the reusability and flexibility of the program, but everything has two sides, it must be measured over and over again.
Next, what is the purpose of obtaining the type information during the runtime?
For example, many software developers prefer to leave some interfaces in their own software. Others can write some plug-ins to expand software functions. For example, I have a media player, I hope that the format of recognition can be easily extended in the future, so I declare an interface:
- public
interface
IMediaFormat
- {
- string
Extension {
get
;}
- Decoder GetDecoder();
- }
This interface contains an extension attribute, which returns a supported extension, and another method returns a decoder object (here I assume a decoder class, this class provides the function of decoding the file stream, which can be derived from the extension plug-in). I can interpret the file stream through the decoder object.
In this case, all decoding plug-ins must derive a decoder and implement this interface. In the getdecoder method, return the decoder object and configure its type name to my configuration file.
In this way, I do not need to know the type of the extended format when developing the player. I only need to obtain the type names of all decoder types from the configuration file, the dynamic creation of media format objects is used to convert them to the imediaformat interface.
This is a typical application of reflection.
4. Use of C # reflection
The basic concept of reflection is the above. What are the applications of reflection?
(1) obtain the type through reflection
There are two methods to obtain the instance object:
At this time, I only get this instance object. The method may be an object reference or an interface reference, but I don't know its exact type. I need to know, that
You can.
You can call the GetType method declared on system. object to obtain the type object of the Instance Object. For example, in a method, I need to determine whether the passed parameter has implemented a certain
Interface. If yes, a method of this interface is called:
- …
-
public
void
Process(
object
processObj )
-
- {
- Type t = processsObj.GetType();
-
if
( t.GetInterface(“ITest”) !=
null
)
- …
- }
- …
Another method to obtain the type is to use the type. GetType and assembly. GetType methods, such:
- Type t = Type.GetType(“System.String”);
Note that we have mentioned the relationship between namespaces and accessories. To find a class, you must specify its accessories, or call GetType on the obtained Assembly instance.
In this Assembly, only the type name can be written, and the other exception is mscorlib. DLL, the type declared in this Assembly can also omit the Assembly name (. by default, mscorlib is referenced during the compilation of net accessories. DLL, unless it is explicitly specified during compilation), for example:
System. String is declared in mscorlib. dll. The above type T = type. GetType ("system. String") is correct.
System. Data. datatable is declared in system. Data. dll, so:
Type. GetType ("system. Data. able") can only get null references.
Required:
- Type t = Type.GetType(
"System.Data.DataTable,System.Data,Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
);
(2) traversing object attributes through reflection
There is a test object class:
- Using
System;
- Using
System. Collections. Generic;
- Using
System. LINQ;
- Using
System. Web;
-
- /**/
/// <Summary>
- /// Summary of test
- /// </Summary>
- Public
Class
Test
- {
Int
ID;
String
Name;
Double
Score;
Public
Test ()
- {
- }
Public
Int
Id {
Get
;
Set
;}
Public
String
Name {
Get
;
Set
;}
Public
Double
Score {
Get
;
Set
;}
- }
-
Sometimes I need to traverse the attributes (names and values) of a test object or I am very lazy and there are many attributes of that object class, you can use the following method:
- Protected
Void
Page_load (
Object
Sender, eventargs E)
- {
- Test test =
New
Test ();
- Test. ID = 1;
- Test. Name =
"Language"
;
- Test. Score = 87.5;
Foreach
(System. reflection. propertyinfo pi
In
Test. GetType (). getproperties ())
- {
- Response. Write (PI. Name +
":"
+ Pi. getvalue (test,
Null
). Tostring () +
"<Br/>"
);
- }
- }
You can also use this method to obtain the browser information:
- Protected
Void
Page_load (
Object
Sender, eventargs E)
- {
/**/
/// Use the reflection mechanism to output the values of each browser attribute
Foreach
(System. reflection. propertyinfo pi
In
Request. browser. GetType (). getproperties ())
- {
Object
OBJ =
New
Object
();
If
(PI. GetType (). basetype. Name =
"Propertyinfo"
)
- {
/**/
/// Obtain the attribute name and its value, and output it on the page
Try
- {
- Response. Write (PI. Name +
"="
+ Pi. getvalue (request. browser,
Null
). Tostring () +
"<Br/>"
);
- }
Catch
- {
Continue
;
- }
- }
- }
- }
(3) dynamically create objects based on types
It is the basis for implementing the abstract factory and the core technology for implementing the abstract factory. Through it, You can dynamically create an object you want. The following example shows how to dynamically create an instance of chinesename or englishname.
- Using
System;
-
Using
System. reflection;
-
Namespace
Testreflection
- {
Class
Reflectionexample
- {
Public
Static
Void
Main ()
- {
- INAME name = abstractfactory. getname ();
- Name. showname ();
- }
- }
-
Public
Class
Abstractfactory
- {
Public
Static
INAME getname ()
- {
// The value of S will be dynamically obtained from web. config later
// Assign s to testreflection. ishishname. The English name is displayed.
String
S =
"Testreflection. chinesename"
;
- INAME name = (INAME) Assembly. Load (
"Testreflection"
). Createinstance (s );
Return
Name;
- }
- }
// Declare an interface that displays the "name" Function
Public
Interface
INAME
- {
Void
Showname ();
- }
-
// Implement the interface to display the Chinese name
Public
Class
Chinesename: INAME
- {
Public
Void
Showname ()
- {
- Console. writeline (
"! "
);
- Console. Readline (
"Chinese name"
);
- }
- }
-
// Implement the interface to display the English name
Public
Class
Englishname: INAME
- {
Void
INAME. showname ()
- {
- Console. writeline (
"Enslish name"
);
- Console. Readline ();
- }
- }
- }