Reflection in. Net (dynamically created type instances)-part.4

Source: Internet
Author: User
Tags set background

Creating objects Dynamically

In the previous section, we learned about reflection, then viewed the type information with reflection, and learned how to create a custom attribute and traverse it with reflection. It can be said that, in the previous sections, we are learning what reflection is , and in the following chapters, we will learn what reflection can do . Before we go into more interesting topics, let's look at how to create an object dynamically.

We created a new console console project called Reflection4 (because this is PART4, you can also get a different name). Then, add a demonstration class that will be described in this article by manipulating the demonstration class:

public class Calculator {

private int x;
private int y;

Public Calculator () {
x = 0;
y = 0;
}

public Calculator (int x, int y) {
this.x = x;
This.y = y;
}
}

1. Creating an object using the parameterless constructor

The above class is very simple, it contains two constructors, one is a constructor with parameters, one is a parameterless constructor, we first look at the reflection, using the parameterless constructor to create the object. There are usually two ways to create objects, one is to use the CreateInstance method of assembly:

Assembly asm = assembly.getexecutingassembly ();
Object obj = asm. CreateInstance ("Reflection4.calculator", true);
Output: Calculator () invoked

The first parameter of CreateInstance represents the string name of the type instance to be created, and the second parameter indicates whether it is case-insensitive (Ignore cases). Notice that CreateInstance returns an object, meaning that if you want to use this object, you need to do a type conversion.

Another way to create an object is to call the static method CreateInstance of the Activator class:

ObjectHandle handler = Activator.CreateInstance (null, "Reflection4.calculator");
Object obj = handler. Unwrap ();

Where CreateInstance's first parameter description is the name of the assembly, NULL indicates the current assembly, and the second parameter describes the type name to be created. Activator.CreateInstance returns a ObjectHandle object that must be unwrap () once to return the object type, which can then be cast to the type we want (in this case, calculator). ObjectHandle is contained in the System.Runtime.Remoting namespace, and it is remoting related, in fact the ObjectHandle class is just a wrapper for the original type for marshaling, and more can be seen in. Net Remoting (application domain)-part.1 this post.

2. Creating an object using the parametric constructor

If we want to create an object from a constructor with parameters, we can use the overloaded method of assembly's Createinstanc ():

Creating objects with parametric constructors
Assembly asm = assembly.getexecutingassembly ();
object[] Parameters = new Object[2]; Define the parameters required by the constructor
Parameters[0] = 3;
PARAMETERS[1] = 5;

Object obj = asm. CreateInstance ("Reflection4.calculator", True, Bindingflags.default, NULL, parameters, NULL, NULL);

Output: Calculator (int x, int y) invoked

Let's take a look at the parameters that CreateInstance needs to provide:

    1. The first two have been explained in the previous section;
    2. BindingFlags in front of us, it is used to restrict the search of type members. Specify default here, meaning not to use Bingdingflags's strategy (you can interpret it as null, but BindingFlags is a value type, so it is not possible to be null, there must be a default value, and that default is its defaults);
    3. The next parameter is binder, which encapsulates the rules of the CreateInstance binding object (Calculator), and we almost always pass NULL in, in effect using predefined defaultbinder;
    4. Next is a object[] array type, which contains the parameters that we pass in, and the parameters of the constructor will use these parameters;
    5. The next parameter is a CultureInfo type, which contains information about language and culture (simple to understand when ToString ("C") should display "¥" and when "$" should be displayed).
Dynamic Call method

Let's look at how to invoke the method dynamically. Note that the call discussed in this article is not to convert the dynamically created objects from the object type to the calculator type before making the method call, which is no different from the "regular call", let's make a call to the method in. Net Reflection. Before proceeding, we add two methods for calculator, one instance method, and one static method:

public int Add () {
int total= 0;
Total = x + y;
Console.WriteLine ("Invoke Instance Method:");
Console.WriteLine (String.Format ("[Add]: {0} plus {1} equals to {2}", X, Y, total));
return total;
}

public static void Add (int x, int y) {
int total = x + y;
Console.WriteLine ("Invoke Static Method:");
Console.WriteLine (String.Format ("[Add]: {0} plus {1} equals to {2}", X, Y, total));
}

There are generally two ways to invoke a method:

    1. Call the InvokeMember () method on the type object of the kind, passing the object on which you want to invoke the method (that is, the calculator type instance you just created dynamically), and specify BindingFlags as InvokeMethod. Depending on the method signature, you may also need to pass parameters.
    2. The Getmethond () method of the type object is used first to get the method object that you want to invoke, that is, the MethodInfo object, and then invoke the Invoke method on the object. Depending on the method signature, you may also need to pass parameters.

It is necessary to note that using InvokeMember is not limited to methods that invoke objects, but also to get fields and properties of objects, in a similar way, this article only describes the most common invocation methods.

1. Calling methods using InvokeMember

Let's look at the first method, the code is simple, just two lines (note that obj was created in the previous section, is an instance of the calculator type):

Type t = typeof (Calculator);
int result = (int) t.invokemember ("Add", BindingFlags.InvokeMethod, NULL, obj, NULL);
Console.WriteLine (String.Format ("The result is {0}", result));

Output:
Invoke Instance Method:
[ADD]: 3 plus 5 equals to 8
The result is 8

In the InvokeMember method, the first parameter describes the name of the method you want to invoke, and the second parameter description is the calling method (because InvokeMember is very powerful, not just the method can be called, but also the properties, fields, and so on.) The details of this enumeration can be found in part.2 or MSDN); The third parameter is the binder,null description using the default binder; The fourth parameter description is called on this object (obj is an instance of the calculator type); The last argument is the array type. Represents the parameters that are accepted by the method.

We're looking at how the static method should be called:

object[] parameters2 = new object[2];
Parameters2[0] = 6;
PARAMETERS2[1] = 9;
T.invokemember ("Add", BindingFlags.InvokeMethod, NULL, typeof (Calculator), parameters2);

Output:
Invoke Static Method:
[ADD]: 6 Plus 9 equals to 15

Let's compare it to the above: first, the fourth argument is passed typeof (Calculator), which is no longer a Calculator instance type, which is easy to understand because we are invoking a static method that is not based on a particular type instance, but on the type itself; , because our static method needs to provide two parameters, we pass the two parameters as an array.

2. Calling methods using Methodinfo.invoke

Let's look at the second way, get a MethodInfo instance first, then call the Invoke method of this instance, and we'll look at how to do it:

Type t = typeof (Calculator);
MethodInfo mi = t.getmethod ("Add", BindingFlags.Instance | BindingFlags.Public);
Mi. Invoke (obj, null);

Output:
Invoke Instance Method:
[ADD]: 3 plus 5 equals to 8
Please press any key to continue ...

In the second line of the code, we first used the GetMethod method to get a method object MethodInfo, specifying BindingFlags as instance and public, because there are two methods named "Add", so specifying a search condition here is a must. Then we call the Add method with Invoke (), the first parameter, obj, is an instance of the calculator type created earlier, indicates that the method is created on that instance, and the second parameter is NULL, stating that the method does not need to supply parameters.

Let's look at how to call a static method in this way:

Type t = typeof (Calculator);
object[] parameters2 = new object[2];
Parameters2[0] = 6;
PARAMETERS2[1] = 9;
MethodInfo mi = t.getmethod ("Add", BindingFlags.Static | BindingFlags.Public);
Oil Invoke (null, PARAMETERS2);
Mi.   Invoke (t, parameters2); You can do that.

Output:
Invoke Static Method:
[ADD]: 6 Plus 9 equals to 15

You can see the same as above, in the GetMethod () method, we specify search bindingflags.static instead of bindingflags.public, because we are going to call the static Add method. In the Invoke () method, it is important to note that the first parameter cannot be passed the calculator type instance, but should pass the type of the calculator or pass null directly. Because static methods are not part of an instance.

Note: The above example shows that using reflection can achieve maximum polymorphism, for example, you can place a DropDownList control on the page, and then specify its items value as the name of the method for your class. Then, in the SelectedIndexChanged event, the method of the class is invoked using the value of values. In the past, you can only write some if else statements, first determine the value returned by DropDownList, and then decide which method to call based on the value. In this way, the compiler does not know exactly which method will be called before the code is run (or before the user chooses an option), which is often said to be late-bound (late binding).

Coding4Fun: Traversing the SYSTEM.DRAWING.COLOR structure

Now that we've covered too many basic methods and theories, let's do something interesting: you know that the color settings for controls in ASP. ForeColor, BackColor, etc., are all a System.Draw.Color structure type. In some cases we need to use a custom color, then we will create a color value Color.fromrgb (125,25,13) in a way like this. But sometimes we find it troublesome, because this number is too intuitive, and we even need to put this value in Photoshop to see what it looks like.

At this point, we might want to use the default color provided by the color structure, that is, its 141 static properties, but these values are still given in the form of names, such as darkgreen, or not intuitive enough, if they can be in the form of color block output to the page is good, This way we will be more convenient to view, and later use will be more convenient. I have implemented it and can click on the link below to view:

Effect preview: http://www.tracefact.net/demo/reflection/color.aspx

Basic implementation

Now let's take a look at the implementation process:

First create the page color.aspx (or other name), then add some styles to the head to control the page display, and then drag and drop a panel control in. The style sheet needs to be aware of the #pncolors Div section, which defines the style of the color blocks that will be displayed on the page; The Panel control with ID pnholder is used to load our dynamically generated div.

<style type= "Text/css" >
body{font-size:14px;}
h1{font-size:26px;}
#pnColors div{
float:left;width:140px;
PADDING:7PX 0;
Text-align:center;
margin:3px;
border:1px solid #aaa;
font-size:11px;
Font-family:verdana, Arial
}
</style>

<body>
<form id= "Form1" runat= "Server" >
<asp:panel id= "pncolors" runat= "Server" ></asp:Panel>
</form>
</body>

Note: If you name the page in order to color.aspx, you need to modify the class name in the code post file, such as: Reflection_color, and the top of the page also needs to be modified to inherits= "Reflection_ Color ", otherwise there is a problem with naming conflicts.

The next step is this: we add a series of Div in Phcolors, which is the color block we're going to show on the page. We set the div's text to the color's name and RGB value, and its background color we set to the corresponding color (other styles of the color block, such as width, border, width is defined in the head). We know that in ASP. NET, there is no div control, only HtmlGenericControl, at which point we'd better define a div to inherit from HtmlGenericControl.

public class Div:htmlgenericcontrol
{
private string name;

Public Div (Color c)
: Base ("div")//Call base class constructor, create a Div
{
THIS.name = C.name; Color name

Set text
This. InnerHtml = String.Format ("{0}<br/>rgb ({1},{2},{3})", Name, C.R, C.G, C.B);

int total = C.R + C.G + c.b;
if (total <= 255)//If the background is too dark, the foreground color is changed to bright tones
This. Style.add ("Color", "#eee");

Set Background color
This. Style.add ("Background", String.Format ("RGB ({0},{1},{2})", C.R, C.G, c.b));
}
}

As we described earlier, this div takes a color type as a constructor parameter, and then in the constructor, it first sets its text to the color name and the individual values of the color (obtained through the color structure's R, G, B property). Then set the div's background color to the corresponding RGB color.

Note: In the above if (total<=255) there, the possible color itself is very dark, if this situation again using the black foreground color then the text will not be able to see clearly, so I added the judgment, if the background is too dark, will be bright color foreground.

OK, now we'll just do a little bit of work in the post code:

protected void Page_Load (object sender, EventArgs e)
{
list<div> list = new list<div> ();

Type t = typeof (Color); The top of the page already contains the using System.Drawing;
Get Properties
Propertyinfo[] Properties = t.getproperties (BindingFlags.Static | BindingFlags.Public);
Div Div;

Traverse Properties
foreach (PropertyInfo p in properties)
{
Get Properties Dynamically
Color C;
c = (color) t.invokemember (p.name, BindingFlags.GetProperty, NULL, typeof (color), null);

div = new Div (c);
List. Add (DIV);
}

foreach (Div item in list) {
PNCOLORS.CONTROLS.ADD (item);
}
}

The code above is straightforward: Create a div list to hold the color blocks that are about to be created. Then get a type instance of color. We then use the GetProperties () method and specify BindingFlags to get all the static public properties. It then iterates through the property and uses the InvokeMember () method to get the property value because it returns an object type, so we need to cast it to a color type. Note here that the InvokeMember BindingFlags is specified as GetProperty, which means to get the property value. The fourth parameter is typeof (color) because the color attribute (such as Darkgreen) is static, not for an instance, and if it is an instance, you need to pass the type instance that called this property. Finally, we create a div based on the color and add it to the list, iterating through the list and adding it to the Panal control with ID pncolors.

Now that's OK, if you open the page, you should see a similar effect:

Sort the list

The page above looks messy because the list is roughly sorted by color name (Transparnet exception), we'd better let the list be sorted based on color. With regard to list sorting, I have discussed it in great detail in the article based on the sort of business objects, so I'm just giving the implementation process, and I'm not telling it. This section is independent of reflection and can be skipped if you are already familiar with the sort.

Add a RadioButtonList control to the page, set AutoPostBack to True, and we require you to sort by name and color value in two ways:

Sort:
<asp:radiobuttonlist id= "Rblsort" runat= "Server" autopostback= "true" repeatdirection= "Horizontal" RepeatLayout= " Flow ">
<asp:listitem selected= "True" >Name</asp:ListItem>
<asp:ListItem>Color</asp:ListItem>
</asp:RadioButtonList>

In the post code, add an enumeration as the basis for sorting:

public enum sortby{
Name,//Sort by name
Color//Dark color value sorting
}

Modify the div class, add the ColorValue field, this field represents the value of the color, and create the nested type Colorcomparer, as well as the method Getcomparer:

public class Div:htmlgenericcontrol
{
private int colorvalue;
private string name;

Public Div (Color c)
: Base ("div")//Call base class constructor, create a Div
{
THIS.name = C.name; Color name

This.colorvalue =//Color value
C.R * * * * * + C.G * + c.b;

Set text
This. InnerHtml = String.Format ("{0}<br/>rgb ({1},{2},{3})", Name, C.R, C.G, C.B);

int total = C.R + C.G + c.b;
if (total <= 255)//If the background is too dark, the foreground color is changed to bright tones
This. Style.add ("Color", "#eee");

Set Background color
This. Style.add ("Background", String.Format ("RGB ({0},{1},{2})", C.R, C.G, c.b));
}

Returns a comparer () for sorting
public static Colorcomparer Getcomparer (SortBy sort) {
return new Colorcomparer (sort);
}

Sort by name by default
public static Colorcomparer Getcomparer () {
Return Getcomparer (Sortby.name);
}

Nested types, for sorting
public class Colorcomparer:icomparer<div>
{
Private SortBy sort;

Public Colorcomparer (SortBy sort) {
This.sort = sort;
}

Implements the Icomparer<t> interface, based on the sort to determine what is based on the one-in-order
public int Compare (Div x, div y)
{
if (sort = = Sortby.name)
return String.Compare (X.name, y.name);
Else
Return X.colorvalue.compareto (Y.colorvalue);
}
}
}

Above the Page_Load event, we add a statement to get the current sort by (enumeration):

SortBy sort;

if (! IsPostBack) {
sort = sortby.name;
} else {
Sort = (SortBy) enum.parse (typeof (SortBy), rblsort.selectedvalue);
}

Before outputting the list to the page, we call the list's Sort method:

List.   Sort (div.getcomparer (sort)); Sort the list

foreach (Div item in list) {
PNCOLORS.CONTROLS.ADD (item);
}

OK, all the work is done, again open the page, you can see similar to the following screen, we can follow the name or color values to sort the list display:

Summarize

This article is divided into three parts. NET reflects an application that dynamically creates objects and invokes object methods (properties, fields). We first learn the most common two ways of dynamically creating objects, and then we discuss the use of the Type.InvokeMember () and Methodinfo.invoke () methods to invoke instance methods and static methods of the type. Finally, we use reflection to traverse the System.Drawing.Color structure and output the color values.

Thanks for reading, I hope this article can bring you help!

Reflection in. Net (dynamically created type instances)-part.4

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.