static types and dynamic types have strengths, and static types allow the compiler to help you find more errors, because the compiler can do most of the checking at compile time. C # is a static type of language, but it adds dynamic types of language features that can be used more efficiently to solve problems.
First, Directory
- 38. Understanding the merits and demerits of dynamic types
- 39. Run-time types that use dynamic types to express generic type parameters
- 40. Declare parameters that accept anonymous types as dynamic
- 41. Using DynamicObject or IDynamicMetaObjectProvider to achieve data-driven dynamic types
- 42. How to use an expression API
- 43. Use expressions to convert deferred bindings to pre-bound
- 44. Minimize the use of dynamic types in the public API
38. Understanding the merits and demerits of dynamic types
C # Dynamic types are intended to allow static code to be more smoothly interacting with other environments that use dynamic types, rather than encouraging dynamic programming in a general scenario using dynamics.
As long as the object contains members at run time, it can be used normally.
If an operand (including this) is a dynamic type, the returned result is also a dynamic type. Finally, however, it is still converted to a static type so that it can be used by other C # code and is perceived by the compiler.
Dynamic typing is the best tool when you need not know the exact type of runtime parsing method. If you can explicitly type during compilation, you can use lambda expressions and functional programming to solve the problem.
Expression tree, a method of creating code at run time (example below).
In most cases, you can use LAMBDA expressions to create generic APIs that allow the caller to dynamically define the code that needs to be executed.
Static types are preferred, static types are more efficient than dynamic types, and dynamic typing and creating expression trees at run time can have a performance impact, even if this is insignificant.
If you can control all the types involved in the program, you can introduce an interface instead of a dynamic type, that is, interface-based programming and have all types that need to support the behavior of that interface implement that interface. The C # type system reduces the errors generated by the code at run time, and the compiler can generate more efficient code.
Dynamic type practices are much more efficient than pure static types, but the difficulty of implementation is much simpler than parsing expression trees.
Here, I use the addition of 3 numbers, the dynamic dynamics, the Func delegate, and the difference between adding using an expression tree:
[TestMethod]PublicvoidTest () {var result1 = adddynamic (2,3); Console.WriteLine ((Int) RESULT1);var result2 = Addfunc (3,4, (x, y) + = x +y); Console.WriteLine (RESULT2);var result3 = Addexpressiontree (4,5); Console.WriteLine (RESULT3); }///<summary>///ADD, dynamic///</summary>///<param name= "a" ></param>///<param name= "B" ></param>///<returns></returns>PrivateDynamic Adddynamic (Dynamic A,Dynamicb) {Return a +b }///<summary>///ADD, using delegates///</summary>///<typeparam name= "T1" ></typeparam>///<typeparam name= "T2" ></typeparam>///<typeparam name= "TR" ></typeparam>///<param name= "a" ></param>///<param name= "B" ></param>///<param name= "func" ></param>///<returns></returns>Private TR addfunc<t1, T2, tr> (T1 A, T2 B, Func<t1, T2, tr>Func) {ReturnFunc (A, b); }///<summary>///ADD, using an expression tree///</summary>///<typeparam name= "T" ></typeparam>///<param name= "a" ></param>///<param name= "B" ></param>///<returns></returns>Private T addexpressiontree<t>(t A, T B) {ParameterExpression Leftoperand = Expression.parameter (typeof (T), "left"); ParameterExpression Rightoperand = Expression.parameter (typeof (T), "right"); Binaryexpression BODY = Expression.add (Leftoperand, Rightoperand); Expression<func<t, T, t>> adder = expression.lambda<func<t, T, t>>(body, Leftoperand, Rightoperand); Func<t, T, t> thedelegate = adder.compile (); return thedelegate (A, b);}}
39. Run-time types that use dynamic types to express generic type parameters
System.linq.enumerable.cast<t> converts the objects in a sequence to T, which enables LINQ to work with IEnumerable.
Convert<t> is more adaptable than cast<t>, but it also performs more work.
40. Declare parameters that accept anonymous types as dynamic
Do not overuse dynamic types, because dynamic calls increase the overhead of the system, even if it is not very large.
In the long run, specific types are easier to maintain, and compilers and type systems provide better support.
Extension methods cannot be based on dynamic object definitions.
41. Using DynamicObject or IDynamicMetaObjectProvider to achieve data-driven dynamic types
The simplest way to create a type with dynamic functionality is to inherit System.Dynamic.DynamicObject. If you can inherit dynamicobject directly, then it is simpler to create dynamic classes.
Implementing IDynamicMetaObjectProvider means that the method Getmetaobject () needs to be implemented.
When you create a dynamic type, you prefer to inherit, and if you have to use other base classes, you can implement the IDynamicMetaObjectProvider interface manually, although all dynamic types have a performance penalty, but this manual implementation of the interface is often a lot more costly.
This is an example of implementing a dynamic type model. In addition to inheriting dynamicobject, you need to rewrite Trygetmemebr () and Trysetmemebr ().
[TestMethod]PublicvoidTest1 () {Dynamic propdynamic =NewDynamicpropertybag (); Propdynamic.now =DateTime.Now; Console.WriteLine (Propdynamic.now); }///<summary>///Dynamic Property Binding Model///</summary>InternalClassDynamicpropertybag:dynamicobject {PrivateReadOnly dictionary<StringObject> _storage =New dictionary<StringObject>();///<summary>///Get property value///</summary>///<param name= "Binder" ></param>///<param name= "Result" ></param>///<returns></returns>PublicOverrideBOOL Trygetmember (GetMemberBinder binder,OutObjectResult) {var key =Binder. Name;If(_storage. ContainsKey (key)) {result =_storage[key];ReturnTrue; } result =Null;ReturnFalse; }///<summary>///Setting property values///</summary>///<param name= "Binder" ></param>///<param name= "Value" ></param>///<returns></returns>PublicOverridebool trysetmember (SetMemberBinder binder, object value) {var key = Binder. Name; try {if _storage. ContainsKey (key)) {_storage[key] = value;} else {_storage. ADD (key, value); } return truecatch (Exception e) {Console.WriteLine (e); return false;}}
42. How to use an expression API
Traditional reflection APIs can be better substituted with expressions and expression trees, and expressions can be compiled directly into delegates.
interface allows us to get a clearer, more maintainable system, and reflection is a powerful late binding mechanism (albeit less efficient) that the. NET framework uses to implement data binding for Windows controls and Web controls.
An example is provided here:
[TestMethod]PublicvoidTest2 () {var result = call<IntString> ((x) = (x *2). ToString ("D")); Console.WriteLine (result); }///<summary>///Call///</summary>///<typeparam name= "T" ></typeparam>///<typeparam name= "TResult" ></typeparam>///<param name= "Op" ></param>///<returns></returns>Private TResult call<t, tresult> (expression<func<t, tresult>>OP) {var exp = op. BodyAsMethodcallexpression;var result =Default(TResult);if (exp = =Null) {ReturnResult }var methodName =Exp. Method.name;var parameters =Exp. Arguments.select (processargument); Console.WriteLine ($"Method name {MethodName}");foreach (var parameterInchParameters) {Console.WriteLine ("Parameters:"); Console.WriteLine ($"\t{parameter. Item1}:{parameter. ITEM2}"); }ReturnResult }///<summary>///Processing parameters///</summary>///<param name= "expression" ></param> ///<returns></returns> private tuple<type, object> processargument (expression expression) {object arg = Span style= "COLOR: #0000ff" >default (object Expression.lambda (Expression.convert (expression, expression. Type)); Type parmtype = L.returntype; arg = L.compile (). DynamicInvoke (); return Tuple.create (Parmtype, arg);}
43. Use expressions to convert deferred bindings to pre-bound
The deferred binding API is implemented using symbol information, and the pre-compiled API does not need this information, and the expression API is the bridge between the two.
Deferred binding is common in the property notification interfaces used in Silverlight and WPF, by implementing the INotifyPropertyChanged and Inotifypropertychanging interfaces to implement the pre-binding of property changes.
44. Minimize the use of dynamic types in the public API
Prefer to use static types in C # and minimize the scope of dynamic types. If you want to use dynamic features all the time, you should choose a dynamic language rather than C #.
To use dynamic attributes in your program, try not to use them in a public interface, which restricts the dynamic type to a single object (or type).
This series
Effective C # Quick notes (i)-C # language habits
Effective C # Quick notes (ii)-. NET Resource Hosting
Effective C # quick Note (iii)-expressing design using C #
Effective C # Quick Notes (iv)-using frames
"Effective C #" Quick Notes (v)-dynamic Programming in C #
Effective C # Quick notes (vi)-C # efficient programming Essentials Supplement
Effective C # Quick notes-dynamic programming in C #