C # simulates a pattern matching and matching value extraction,

Source: Internet
Author: User

C # simulates a pattern matching and matching value extraction,

Abstract mode Description: msdn describes it as follows: "Mode" is a rule used to convert input data. The mode will be used in the entire F # language. It compares data with one or more logical structures in multiple ways, splits the data into various components, or extracts information from the data.

Pattern matching has its own definition, and there are also many types. Here we process relatively complex [structure comparison] and [data extraction] (sometimes also called type check and conversion ).

Simply put, "check an object to see if there are attribute members that we are interested in. If so, retrieve these Member values for future use ".

1. Structure comparison

Measure the test taker's knowledge about the following objects:

Code 01

 var o = new            {                a = 2,                b = 3,                d = 0,                c = new                {                    a1 = 7,                    b1 = 2,                    e = new                    {                        name = "aaa",                        Id = 0                    }                }            };

  

When we know the specific type, we can get the relevant value through attribute access,

Code 02

int r1=o.a;int r2=o.c.a1;string r3=o.c.e.name;

However, when the type is not clear, for example:

Code 03

method1(object obj)

In method1, how can we quickly and conveniently obtain the relevant property values?

First, we know that the problem occurs because the "type is not clear". The first thing we need to do is to restore the type information;

Before restoring the type information, describe the information we want to obtain. Take code 02 as an example,

1. You want o to have an attribute named a, type int.

2. You want o to have an attribute named c and an attribute named a1 ON c, type int.

3. You want o to have a property named c, a property named e on c, and a property type named name on e

......

It is not difficult to find that a. the type information we want to describe is not necessarily the same as the original type, but only the desired part;

B. the hierarchical relationship can be correctly expressed in the type information to be described.

C. You must be able to describe all types of attribute members.

D. Clearly Understand The expected type information

E. It is best to use the technical means directly provided in the language environment

Based on the preceding description, anonymous objects are used to describe the type, which is simple and can satisfy the preceding five points at the same time.

Code 04

 var typeinfo = new            {                a = 3,//default(int)                c = new                {                    a1 = 1,                    e = new                    {                        name = default(string)                    }                }            };

Note: When the type description is used, the attribute value is meaningless. You can use default (type). Here, the value is used for subsequent comparison.

 

With the type description, the type check is relatively simple. We can check whether there are corresponding members on the target object one by one based on the type description information.

Use reflection directly.

Code 05

If (pi. name = npi. name & pi. propertyType = npi. propertyType) {return true. result (new GetValue (o => npi. getter (o); // for extension methods, see code 06}


Code 06

Public struct Result <T> {public bool OK; public T Value; public Result (bool OK, T resultOrReason) {this. OK = OK; this. value = resultOrReason;} public static implicit operator Result <T> (bool value) {return new Result <T> (value, default (T ));} public static explicit operator bool (Result <T> value) {return value. OK;} public static bool operator = (Result <T> a, Result <T> B) {return. equals (B );} Public static bool operator! = (Result <T> a, Result <T> B) {return! A. equals (B);} public override bool Equals (object obj) {var r = (Result <T>) obj; return this. OK = r. OK & object. equals (this. value, r. value);} public override int GetHashCode () {return this. OK. getHashCode () + (this. value = null? 0: this. Value. GetHashCode ());}}Both bool and result are returned.
Delegate:
// Return all the filter values of the instance: public delegate IEnumerable <object> GetAllValues (object instance); // return a value of public delegate object GetValue (object instance) on the instance );

 

// Extension Method


// Bool + Result public static Result <Value> (this bool state, Value value) {return new Result <Value> (state, value );} // attribute value, reflecting public static object Getter (this PropertyInfo info, object instance) {return info. getValue (instance);} // New instance, reflecting public static object New (this Type t, params object [] args) {return args. isEmpty ()? Activator. CreateInstance (t): Activator. CreateInstance (t, args );}

 

Considering that the structure may be nested, the main code is as follows:

Code 07

 

 1      public static Result<GetAllValues> MatchType(this Type pattern, Type target) { 2             var pis = pattern.GetProperties(); 3             var tpis = target.GetProperties(); 4             if (pis.Length < tpis.Length) 5             { 6                 7                 var fac = new List<GetValue>(); 8                 for (int i = 0; i < pis.Length; i++) 9                 {10                     var pi = pis[i];11                     var r = pi.MatchProp(tpis);12                     if (r.OK)13                     {14                         fac.Add(r.Value);15                         continue;16                     }17                     return false;29                 }30                 return true.Result(new GetAllValues(o => fac.Select(c => c(o))));31             }32             return false;33         }34           static Result<GetValue> MatchProp(this PropertyInfo pi, IEnumerable<PropertyInfo> target) {35              36             var npi =  target.FirstOrDefault(c => c.Name == pi.Name)??(pi.Name=="_"?target.FirstOrDefault(c=>c.PropertyType==pi.PropertyType):null);37             if (npi != null) {38                 if (pi.PropertyType.IsAnonymous() )39                 {40                     var r = pi.PropertyType.MatchType(npi.PropertyType);41                     if (r.OK) {42                         return true.Result(new GetValue(o => pi.PropertyType.New(r.Value(npi.Getter(o)).ToArray())));43                     }44                 }45                 else if (  pi.PropertyType == npi.PropertyType)46                 {47                     return true.Result(new GetValue(o => npi.Getter(o)));48 49                 }50             }51             return false;52 53         }

Code Description:

Attribute use name + attribute type for check

If the type description contains an anonymous type attribute (line: 38), perform a hierarchical check.

When the attribute name is '_', ignore the attribute name, that is, match the first attribute of the same type (only one inspection Extension Method: special processing can be performed through the attribute information)

Returns the value function for the target object after successful matching.

 

2. Target value Extraction

In c #, variables cannot be conveniently defined dynamically. Therefore, after the structure check is completed, the returned Result is {true/false, value function} (Result <GetAllValues> ).

For ease of use, the extracted values must be provided to the user in a friendly way. Here, a new instance of the structure description type (anonymous type) is directly created as the return result.

With generic

        public static Result<TResult> AsPattern<TPattern, TResult>(this TPattern pattern, object matchobj, Func<TPattern, TResult> then) {            var matchType = matchobj.GetType();            var patternType = typeof(TPattern);            var matchResult = patternType.MatchType(matchType);            if (matchResult.OK) {                var patternInstance = patternType.New(matchResult.Value(matchobj).ToArray());                return true.Result(then((TPattern)patternInstance));            }            return false;        }

Call:

 

1 var result = typeinfo. asPattern (o, (c) => c ). value; // The result type is the typeinfo type in code 04. 2 // result. a; 3 // result. c. a1; 4 // result. c. e. name;

 

3. Multiple Pattern Matching and method matching:

After processing in a single mode, processing in multiple modes is a simple collection.

Method matching: If you need to do this in c #, it can be easily performed (without the ref out method). Use it with caution.

1. description using anonymous delegation: new {test = default (func <string, object>)} = expect a method named test with the string parameter that returns the object

2. First, check the attributes: check whether there are any attributes with the name "test" and the type "func <string, object>" in the target method. If the attribute does not exist, search for the attribute in the target method.

Key code

Method signature judgment

Public static bool SignatureEqual (this MethodInfo mi, Type retType, IEnumerable <Type> paramTypes) {return mi. returnType = retType & paramTypes. sequenceEqual (mi. getParameters (). select (p => p. parameterType ));}
// Whether the parameters and return values of the methods and delegation types are consistent. public static bool SignatureEqual (this MethodInfo mi, Type delegateType) {var cmi = delegateType. getMethod ("Invoke"); return mi. signatureEqual (cmi);} public static bool SignatureEqual (this MethodInfo mi, MethodInfo nmi) {return mi. signatureEqual (nmi. returnType, nmi. getParameters (). select (p => p. parameterType ));}

Return method call after the signatures are consistent

new GetValue(o => m.CreateDelegate(pi.PropertyType, o))//m MethodInfo

After the matching is complete, you can directly call it through result. test ("aaa ").

 

 

 
 

 

 

 

 

 

 

 

Related Article

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.