Dynamic LINQ query (dynamically construct Expression <T> Expression Tree)
What is dynamic LINQ query? The compiling of LINQ is static, because C # is designed based on the principle of the static type system, and the type has been determined at the time of writing, that is, the query to be executed is known at the time of compilation, what are conditions and sorting methods. In most application scenarios, We need to query the data source based on the user's choice. In the past, we used to concatenate the query SQL string through judgment, but now we are faced with strong-type LINQ queries. Can we easily perform similar queries. In fact, there is nothing mysterious. The basic implementation principle is to dynamically construct an Expression Tree to implement IQueryable <T> interface query.
In fact, the most critical factor that can be executed by dynamic LINQ queries is that Expression <T> objects can be dynamically compiled into executable delegate objects, the delegated object is an executable code segment that can be directly used, which provides the foundation for dynamic LINQ query. The query Expression method of the IEnumerable <T> type knows that its execution does not directly accept Expression <T> type objects. Can dynamic LINQ work on the IEnumerable <T> interface? Actually, there is a very hidden trick hidden in the IQueryable <T> Extension Method object Queryable, that is, the AsQueryable <T> method, it returns an EnumerableQuery object that implements the IQueryable <T> interface. The implementation content of this object is not very complex, compile the dynamically spliced Data Structure Expression <T> object into an executable anonymous function, and then directly execute the query. [Wang qingpei has all rights reserved. For more information, please sign it.]
Let's take a look at the key point of the EnumerableQuery object. It must be the place where the Expression <T> object is Compiler.
Private IEnumerator <T> GetEnumerator ()
{
If (this. enumerable = null)
{
EnumerableRewriter rewriter = new EnumerableRewriter ();
Expression <Func <IEnumerable <T> expression2 =
Expression. Lambda <Func <IEnumerable <T> (rewriter. Visit (this. expression), (IEnumerable <ParameterExpression>) null );
This. enumerable = expression2.Compile (); // (1) Key
}
Return this. enumerable. GetEnumerator ();
}
In the "(1) Emphasis" in the above code, we can clearly see that the expression tree is dynamically compiled and then executed, here we can see why the IEnumerable <T> object must be converted to an IQueryable <T> object. This eliminates the dynamic query bottlenecks between the IEnumerable <T> and IQueryable <T> interfaces.
Why do we need dynamic LINQ queries? As mentioned above, we cannot write Lambda expressions at runtime. We all know that Lambda expressions are compiled into Expression Tree objects at the end, therefore, we can dynamically construct the Expression object at runtime, so that we can pass the dynamically constructed Expression tree object directly to the required method. If the queried data object is IEnumerable <T>, It is dynamically compiled into executable delegates and then executed directly, if IQueryable <T> is queried, it is automatically parsed and executed by the provider.
Here is a simple dynamic query example:
Student [] StudentArrary = new Student [3]
{
New Student () {Name = "Wang qingpei", Age = 24, Sex = "male", Address = "Nanjing, Jiangsu "},
New Student () {Name = "Chen Yu and", Age = 23, Sex = "female", Address = "Yancheng, Jiangsu "},
New Student () {Name = "Golden Source", Age = 22, Sex = "female", Address = "Huai 'an, Jiangsu "}
};
This is a set of data. For simple testing, it is no longer so troublesome as to use the Linq to SQL data source. We will use the dynamic build expression tree as the query logic. In the past, our Lambda was useless at this time, and we could not build the delegate type at runtime.
The requirement is to accept the input of a Name value from the interface. You only need to write the Name directly for the LINQ query.
Var list = from I in StudentArrary where I. Name = "Wang qingpei" select I;
However, we need to dynamically construct an Expression Tree to execute the query. Any node in the Expression tree has the corresponding Expression derived type, so we only need to assemble the relevant types. Since the sample program I created is of the console program type, we will briefly demonstrate how to build an Expression Tree.
ParameterExpression parameter = Expression. Parameter (typeof (Student), "stu"); // The parameter name on the left of the binary operator
// Indicates the Name attribute in "stu. Name" of the "stu" parameter. The Name attribute must be the metadata obtained by reflection, so that the framework can find it.
MemberExpression property = Expression. MakeMemberAccess (parameter, typeof (Student). GetMember ("Name") [0]);
// Indicates the Constant Value
Console. WriteLine ("enter the name of the person you want to query :");
ConstantExpression name = Expression. Constant (Console. ReadLine (); // read the value from the user input stream
BinaryExpression binary = Expression. MakeBinary (ExpressionType. Equal, property, name); // concatenation = Operator left and right
// The complete expression is for Lambda
LambdaExpression lambda = Expression. Lambda (binary, parameter );
// The important thing is that we directly convert the complete Lambda expression to the executable delegate.
Func <Student, bool> wheredelegate = lambda. Compile () as Func <Student, bool>;
// Put the compiled executable delegate directly into the Where Method for execution
Var list2 = StudentArrary. AsQueryable <Student> (). Where (wheredelegate );
Foreach (var I in list2)
{
Console. WriteLine ("query list :");
Console. WriteLine ("Name: {0}, Age: {1}, Address: {2}", I. Name, I. Age, I. Address );
}
Console. ReadLine ();
Legend:
This example focuses on how to dynamically build the logic. Similar functions can be encapsulated for future reuse according to different project requirements. If you think it is difficult to manually write an expression tree, we suggest you find a helper class that can print out the Lambda expression's object tree, and then it is much easier to write to this tree.
There are not many third-party APIs for Dynamic LINQ, and Dynamic. cs is commonly used. I have never used them. It is easier to read relevant documents. Its internal principle is actually the Dynamic Construction of Expression Tree, but this part of work has been done by people, and we use it a lot easier. [Wang qingpei has all rights reserved. For more information, please sign it.]
6]. DLR Dynamic Language Runtime (Dynamic Language Runtime Based on CLR)
Along the way from C #1, it has become more and more powerful, and the. NET platform has become omnipotent. Many people have been biting. NET cannot be cross-platform, dynamic objects are not supported, and unmanaged objects are not supported for other reasons. However, what they do not know is. NET has quietly made a major move, that is, embedding the Dynamic Language Runtime Environment in the static language runtime. I don't think Microsoft can support the so-called shortcomings, but it does have its intention.
The Dynamic Language is running in. the runtime environment based on CLR introduced in NET4.0 aims to learn from the advantages of Dynamic Language Runtime in static languages, such as powerful type conversion, this is especially important when designing the application development framework. Any good feature requires a large area of use mode to become more perfect.
Speaking of dynamic running, we have to mention the Exciting Object Features defined by var in JS, if you do not pay attention to the troubles that may occur during the design of the framework, it is difficult to find the good or bad performance between dynamic running and static languages. Obviously, when we define a data type object, we can no longer use it for other types during later runtime. Let's look at a simple example:
Dynamic obj = 1; // integer
Obj = "1"; // string
Obj = new {Name = "Wang qingpei", Age = 24, Address = "Jiangsu"}; // anonymous object type
At runtime, we can design the object type at will. I am bold enough to assume that we can use dynamic runtime features to design a system similar to artificial intelligence and provide a basic prototype, then, any object tree is constructed based on the user's own way of thinking. Technological Research is a good direction, and enterprise applications may still be discussed.
In the past, it was difficult for us to dynamically add attributes, behaviors, and events to objects during runtime. We can freely add what we wanted during runtime using dynamic languages.
Let's take a simple example. We can dynamically construct an object type at runtime. In the past, we only used dynamic compilation and CodeDom technology to implement it. This will be quite simple.
Static void Main (string [] args)
{
Dynamic objModel = new ExpandoObject (); // You can dynamically add ExpandoObject objects for attributes, methods, and events during initialization.
ObjModel. Name = "Wang qingpei"; // set the attribute value
ObjModel. Age = 24;
ObjModel. WriteEvent = null; // define the delegate field for storing events
ObjModel. WriteEvent + = new Action <string> (WriteName); // sets the event method.
ObjModel. WriteEvent (objModel. Name + objModel. Age );
Console. ReadLine ();
}
Public static void WriteName (string info)
{
Console. WriteLine (info );
}
A simple example tells us that we can write dynamic object functions in JS in C #, but it is not very mature yet, and members of dynamic objects do not have smart prompts, it should have not been used in a large area, and it will certainly be a big meal in the future. [Wang qingpei is copyrighted. Please give a signature for reprinting]
Summary: The basic usage principles of the linq framework are all over. Next we will learn how to enable LINQ to query our custom data sources. Many of my friends like writing their own ORM frameworks. Are you sure you have to support the LINQ? Later, we will explain in detail how to extend the two heavyweight interfaces, IQueryable and IQueryableProvider. Only the two of them can let us talk to LINQ. These two interfaces are mysterious.