User code serialization: The Power of the CodeDom

Source: Internet
Author: User
Tags readable serialization


Vs. NET, the main object persistence mechanism is handled through direct code sending. You have seen this in all the InitializeComponent methods that are contained in web and Windows Forms. This procedure is also shown in the Component-inheritance type. Two properties determine this behavior: System.ComponentModel.Design.Serialization.RootDesignerSerializerAttribute and System.ComponentModel.Design.Seri Alization. DesignerSerializerAttribute., as at the beginning of the discussion of the DesignerAttribute, there is an obvious difference between the root and the standard string. But unlike DesignerAttribute, the standard (non-root) string is always used, and the root string is used when the widget is also the root component of the design. It's usually just a custom non-root string. The indicator for this non-root string is that the IComponent interface already contains a root string.



However, it does not provide properties for designing a regular string. However, the special implementation of IComponent provides this property. For example:




And

 [Designerserializer (typeof (System.Windows.Forms.Design.ControlCodeDomSerializer)), 
typeof ( CodeDomSerializer)]
public class System.Windows.Forms.Control:Component

   Note: Both have their own unique serialization, because the way Windows Forms are saved to code differs greatly from how Web forms are saved to code. The former serialize all the values and settings of the InitializeComponent method, while the latter is only stored in the code-behind event handler connection attachment because the control properties are saved in the ASPX page.

   You must have noticed that InitializeComponent always sends code in the correct language, regardless of whether the control is used in a vb.net project or in a C # project (or other language that can be used for this purpose). Because. A new feature in net (this feature is called CodeDom.) The CodeDom is a set of types that allows us to write object hierarchies that represent more common language constructs, such as: type, realm, and attribute declarations, event connection attachments, try ... Catch.. Finally blocks and so on. They allow us to create an abstract syntax tree (AST) called the intended target code. Abstract syntax tree (AST) is abstracted, it does not represent vb.net or C # code, but represents constructs themselves. The things that

    asts Pass to the integrated development environment are the ones that contain code that they expect to save. The integrated development environment creates a System.CodeDom.Compiler.CodeDomProvider-inheritance type in turn, System.CodeDom.Compiler.CodeDomProvider-The inheritance type exactly matches the current project , such as: Microsoft.CSharp.CSharpCodeProvider Or Microsoft.VisualBasic.VBCodeProvider. This object is ultimately responsible for transferring the AST in a specific language code, which has already been embedded in the InitializeComponent method.

    CodeDom is not very complex, let's learn the CodeDom quickly.

CodeDom syntax

The best approach is to learn the CodeDom by example, so take a look at some C # code and its equivalent CodeDom statements (we assume they all happen within the type). The downloaded code includes a project to check the CodeDom in the Codedomtester folder. It is a simple controller application that has two skeleton methods on this controller application: GetMembers and Getstatements. You can put the sample CodeDom code into these two methods, and look at the results of the output.
C#:

private string Somefield;

Codedom:

Codememberfield field = new Codememberfield (typeof (String), "Somefield");

All type-level member representations Codememberevent, Codememberfield, CodeMemberMethod and Codememberproperty, are inherited from CodeTypeMember, The private and final properties are owned by default.

C#:

public string Somefield = "somevalue";

Codedom:

Codememberfield field = new Codememberfield (typeof (String), "Somefield");
Field. Initexpression = new CodePrimitiveExpression ("somevalue");
Field. Attributes = Memberattributes.public;

C#

This.somefield = GetValue ();

Codedom:






Note: The actual length of the verbosity increases by several times. Also note that the GetValue () method in the C # code has an implicit reference to this and must be displayed in the CodeDom.

C#

This. GetValue ("Someparameter", This.somefield);

Codedom








We call a hypothetical overload of the same method. Note Create a method invocation representation first, and then specify a method reference and a method name for it (point to this). There are two additional parameters, and the second is a reference to this field.

If you want to avoid endless and useless variable declarations, you can create statements without using a temporary variable. This makes the code less readable and easier to read, but more compact. A good technique for creating these syntaxes is to consider the target code, generating the target code from the inside to the outside. For example, in the above code.

This. GetValue ("Someparameter", This.somefield);

First create the parameters, then consider the method reference, and once you want to do the work, write down these things:







The last thing we see is a this.somefield, then the original notation. This is passed as an initialization notation for the parameter array of the method invocation. Then you get the This.somefield, and finally the This.somefield raises the actual call.

Note that the right indentation can provide a great deal of help, but most of the work needs to be done by yourself, especially with a nest-like level of work. In order to achieve some legitimacy, the most important nesting is the array initialization (mentioned above). It is also recommended to place the expected C # (or vb.net) output code on the multi-line statement, so everyone knows what you are trying to send.

These are the types that define all the cross-language features. But let's look at the specific persistence code that needs to be provided for the extended attribute.

Send CodeDom

We'll need to connect a custom string to the base controller, for custom persistence, and to send code to save the view map and any potential code we need.

[Designerserializer (typeof (Controllercodedomserializer),
typeof (CodeDomSerializer))]
public class Basecontroller:component, IExtenderProvider

Custom serialization must inherit from CodeDomSerializer. This basic abstract type (this basic abstract type bit System.ComponentModel.Design serialization) contains two abstract methods that must be implemented.








Whenever an object needs to be saved, the Serialize method is invoked. The return value must be an object of type CodeStatementCollection (this type includes code to save). Similarly, the CodeObject parameter in the Deserialize method includes the previously sent statement.

In the overview, we'll talk about the sample root component, which is designed with the root designer. This process occurs in almost all artifacts (and controls) in the root component world. What really happens is that the integrated development environment executes most of the code in InitializeComponent, recreating objects as if they were in the runtime. We say most, not all, because only the statements that modify the artifacts in the problem are invoked: for example, property settings and method calls in them. By customizing the deserialize approach, we have the opportunity to interact in the process of rebuilding during the design period. This is usually not necessary, so most of the time we pass the ball to the initial widget Componentcodedomserializer, which basically implements this code. Componentcodedomserializer In order to get the type of the IDesignerSerializationManager, we use the Getserializer method of the parameters we receive. There are other useful methods for this object, which we will use later.

So the deserialize implementations are usually like this:








Retrieving the component initial serialization is a common use of the manager. Because deserialization is usually the same. We will put it in the base type and will generate the base type from the controller's serialization.

Internal abstract class Basecodedomserializer:codedomserializer
{
Protected CodeDomSerializer Getbasecomponentserializer (
IDesignerSerializationManager manager)
{
Return (CodeDomSerializer)
Manager. Getserializer (typeof (Component), typeof (CodeDomSerializer));
}

public override Object Deserialize (
IDesignerSerializationManager Manager, Object CodeObject)
{
Return Getbasecomponentserializer (manager). Deserialize (manager,
CodeObject);
}
}

Additional public methods will be added later for this type. Now we need to serialize the process, we need to iterate through all the dictionaryentry elements of Hashtable, send the following code, in order to save the Configuredviews attribute.



Another common approach is to have the initial widget string perform its own work. Then add our custom statements. In this way, we avoid saving common component properties ourselves. So the skewer starts performing these tasks:











It is important to realize that even if the root component is the base controller itself, it will still invoke the serialization device. In this case, we do not need to maintain custom code, because when it is used inside another widget (for example, a page or a form), it is used primarily for the basics. To consider this issue, we require the use of a previously used IDesignerHost service to check its rootcomponent properties. IDesignerSerializationManager implements IServiceProvider, so we use the usual GetService method to complete it.




When serializing/deserializing code, the basic CodeDomSerializer type can work together with some useful methods. When accessing the Configuredviews property, this process is accomplished through a reference to the actual controller that is running (the value parameter). A Help method in the base type creates the correct CodeDom object, which is used in a CodeDom graph.
CodeExpression Cnref = serializetoreferenceexpression (manager, value);
You can now use CodeExpression to create a property reference.


We mainly define two variables, simplify a notation that will be established below, and look again at the sample target method invocation:


We have created the first part of the Configuredviews property access, and the next part is:
Call to Codemethodinvokeexpression:add
codeexpression[]: The parameter of the method invocation.
codeprimitiveexpression: "txtID" meta string value.
codeobjectcreateexpression: The new View Info section.
codeprimitiveexpression: Each unary string value passed to the constructor

So the code is:

Collapse
Basecontroller cn = (Basecontroller) value;
CodeExpression Cnref = serializetoreferenceexpression (manager, value);

CodePropertyReferenceExpression Propref =
New CodePropertyReferenceExpression (Cnref, "configuredviews");
Iterate the entries
foreach (DictionaryEntry CV in CN. Configuredviews)
{
ViewInfo info = (ViewInfo) CV. Value;
if (info. ControlID!= String.Empty && info. Controlproperty!= NULL &&
Info. Model!= String.Empty && info. Modelproperty!= String.Empty)
{
Generates:
Controller. Configuredviews.add (Key, new ViewInfo ([values]);
Statements. ADD (
New CodeMethodInvokeExpression (
Propref, "Add",
New codeexpression[] {
New CodePrimitiveExpression (CV. Key),
New CodeObjectCreateExpression (
typeof (ViewInfo),
New codeexpression[] {
New CodePrimitiveExpression (info. ControlID),
New CodePrimitiveExpression (info. Controlproperty),
New CodePrimitiveExpression (info. Model),
New CodePrimitiveExpression (info. Modelproperty)}
) }
));
}
}
Note: Proper indentation is helpful in making more readable statements. Incidentally, only two temporary variables are now declared, and these two temporary variables can also be omitted.
We can use the following to add comments to the code:


With the widget, back to the form, in the associated inializecomponent section, we can have the following code.











The code generator is perfect for all types of references, because the developer will not be guaranteed to add the necessary using sentences to the type.
When the code is generated, we can also send the found error. For example, if you check that these properties are not established correctly, you can also send the found error.
 Collapse 
if (info. ControlID!= String.Empty && info. Controlproperty!= null &&
Info. Model!= String.Empty && info. Modelproperty!= String.Empty)
{
//report errors if necessary
Object CTL = Manager. getinstance (info. ControlID);
if (ctl = null)
{
Manager. ReportError (String.Format ("control ' {0} ' associated" +
) with the view mapping in "+" controller ' {1} ' doesn ' t "+ "exist in the page.", info. ControlID, manager. GetName (value)));
Continue;
}
if (ctl. GetType (). GetProperty (info. controlproperty) = = null)
{
Manager. ReportError (String.Format ("control property ' {0} '" +
"control ' {1} ' associated ' +") with the view mapping in CONTR Oller "+
" ' {2} ' doesn ' t exist. ", info. Controlproperty, Info. ControlID,
Manager. GetName (value)));
Continue;
}
   Note that we use other manager methods to design error messages, getinstance and GetName allow us to find the object references and their respective names again. When an error is found, the invalid setting is effectively removed by using continue to avoid the serialization of invalid settings. When there is an invalid value here, the widget user can see something like the following:

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.