4.Operator Overload Methods
allow a type to define how operators should manipulate instances of the type.
1.The CLR doesn’t know anything about operator overloading because it doesn’t even know what an operator is.
programming language defines what each operator symbol means and what code should be generated when these special symbols appear.
Although the CLR doesn’t know anything about operators, it does specify how languages should expose operator overloads so that they can be readily consumed by code written in a different programming language.
Each programming language gets to decide for itself whether it will support operator overloads, and if it does, the syntax for expressing and using them.
As far as the CLR is concerned, operator overloads are simply methods.
2.programming language determines whether or not you get the support of operator overloading and what the syntax looks like.
When you compile your source code, the compiler produces a method that identifies the behavior of the operator.
The CLR specification mandates that operator overload methods be public and static methods.
In addition, C# (and many other languages) requires that at least one of the operator method’s parameters must be the same as the type that the operator method is defined within
3.
相关知识:
1.it enables the C# compiler to search for a possible operator method to bind to in a reasonable amount of time.
The compiler emits a metadata method definition entry for a method called op_Addition; the method definition entry also has the specialname flag set, indicating that this is a “special” method.
When language compilers (including the C# compiler) see a + operator specified in source code, they look to see if one of the operand’s types defines a specialname method called op_Addition whose parameters are compatible with the operand’s types.
If this method exists, the compiler emits code to call this method. If no such method exists, a compilation error occurs.
The CLR specification defines many additional operators that can be overloaded, but C# does not support these additional operators.
Therefore, they are not in mainstream use, so I will not list them here.
If you are interested in the complete list, please see the ECMA specifications(www.ecma-international.org/publications/standards/Ecma-335.htm) for the Common Language Infrastructure (CLI), Partition I, Concepts and Architecture, Sections 10.3.1 (unary operators) and 10.3.2 (binary operators).
2.If you examine the core numeric types (Int32, Int64, UInt32, and so on) in the Framework Class Library (FCL), you’ll see that they don’t define any operator overload methods.
The reason they don’t is that compilers look specifically for operations on these primitive types and emit IL instructions that directly manipulate instances of these types.
If the types were to offer methods and if compilers were to emit code to call these methods, a run-time performance cost would be associated with the method call.
Plus, the method would ultimately have to execute some IL instructions to perform the expected operation
anyway.
This is the reason why the core FCL types don’t define any operator overload methods.
Here’s what this means to you: if the programming language you’re using doesn’t support one of the core FCL types, you won’t be able to perform any operations on instances of that type.
Operators and Programming Language Interoperability
Operator overloading can be a very useful tool, allowing developers to express their thoughts with succinct code.
1.However, not all programming languages support operator overloading
When using a language that doesn’t support operator overloading, the language will not know how to interpret the + operator (unless the type is a primitive in that language), and the compiler will emit an error.
2.If you are using a language that doesn’t support + operator overloading to be defined in a type.obviously, this type could still offer an op_Addition method
From C#, you might expect that you could call this op_Addition method by using the + operator, but you cannot.
When the C# compiler detects the + operator, it looks for an op_Addition method that has the specialname metadata flag associated with it so that the compiler knows for sure that the op_Addition method is intended
to be an operator overload method.
Because the op_Addition method is produced by a language that doesn’t support operator overloads, the method won’t have the specialname flag associated with it, and the C# compiler will produce a compilation error.
Of course, code in any language can explicitly call a method that just happens to be named op_Addition, but the compilers won’t translate a usage of the + symbol to call this method.
5.Conversion Operator Methods
convert an object from one type to an object of a different type.
1.When the source type and the target type are a compiler’s primitive types, the compiler knows how to emit the necessary code to convert the object.
2.If the source type or target type is not a primitive, the compiler emits code that has the CLR perform the conversion (cast).
the CLR just checks if the source object’s type is the same type as the target type (or derived from the target type).
3.it is sometimes natural to want to convert an object of one type to a completely different type.
To make these conversions, the Rational type should define public constructors that take a single parameter: an instance of the type that you’re converting from.
should also define public instance ToXxx methods that take no parameters (just like the very popular ToString method). Each method will convert an instance of the defining type to the Xxx type.
The ability to do these conversions can be quite handy, and when designing a type, you should seriously consider what conversion constructors and methods make sense for your type
4.some programming languages (such as C#) also offer conversion operator overloading.
Conversion operators are methods that convert an object from one type to another type.
You define a conversion operator method by using special syntax.
The CLR specification mandates that conversion overload methods be public and static methods
In addition, C# (and many other languages) requires that either the parameter or the return type must be the same as the type that the conversion method is defined within
The reason for this restriction is that it enables the C# compiler to search for a possible operator method to bind to in a reasonable amount of time.
5.For conversion operator methods, you must indicate whether a compiler can emit code to call a conversion operator method implicitly or whether the source code must explicitly indicate when the compiler is to emit code to call a conversion operator method.
In C#, you use the implicit keyword to indicate to the compiler that an explicit cast doesn’t have to appear in the source code in order to emit code that calls the method.
The explicit keyword allows the compiler to call the method only when an explicit cast exists in the source code.
After the implicit or explicit keyword, you tell the compiler that the method is a conversion operator by specifying the operator keyword.
After the operator keyword, you specify the type that an object is being cast to;
in the parentheses, you specify the type that an object is being cast from.
compiling:
1.the C# compiler detects the casts (type conversions) in the code
internally generates IL code
calls the conversion operator methods defined by the Rational type.
what are the names of these methods? Well, compiling the Rational type and examining its metadata
shows that the compiler produces one method for each conversion operator defined.
As you can see, methods that convert an object from one type to another are always named op_Implicit or op_Explicit.
2.should define an implicit conversion operator only when precision or magnitude isn’t lost during a conversion, such as when converting an Int32 to a Rational.
However,should define an explicit conversion operator if precision or magnitude is lost during the conversion,as when converting a Rational object to an Int32
If an explicit conversion fails, you should indicate this by having your explicit conversion operator method throw an OverflowException or an InvalidOperationException.
3.The CLR fully supports the ability for a type to define multiple methods that differ only by return type.
example:The two op_Explicit methods take the same parameter, a Rational. However,the methods differ by their return type, an Int32 and a Single. This two methods that differ only by their return type
However, very few languages expose this ability. As you’re probably aware, C++, C#, Visual Basic, and Java are all examples of languages that don’t support the definition of multiple methods that differ only by their return type.
A few languages (such as IL assembly language) allow the developer to explicitly select which of these methods to call.
IL assembly language programmers shouldn’t take advantage of this ability because the methods they define can’t be callable from other programming languages
Even though C# doesn’t expose this ability to the C# programmer, the compiler does take advantage of this ability internally when a type defines conversion operator methods.
5.C# has full support for conversion operators.
When it detects code where you’re using an object of one type and an object of a different type is expected, the compiler searches for an implicit conversion operator method capable of performing the conversion and generates code to call that method.
If an implicit conversion operator method exists, the compiler emits a call to it in the resulting IL code.
If the compiler sees source code that is explicitly casting an object from one type to another type, the
compiler searches for an implicit or explicit conversion operator method.If one exists, the compiler
emits the call to the method.
If the compiler can’t find an appropriate conversion operator method, it issues an error and doesn’t compile the code.
6.C# generates code to invoke explicit conversion operators when using a cast expression;they are never invoked when using C#’s as or is operators.
6.Extension Methods
what C#’s extension methods feature does.
The first problem is that a programmer who wants to get the index of a character within a StringBuilder must know that the StringBuilderExtensions class even exists
The second problem is that the code does not reflect the order of operations that are being performed on the StringBuilder object, making the code difficult to write, read, and maintain.
进阶:
both versions of this code that affects understanding the code’s behavior
优化:
look how great this is in terms of code maintainability.the compiler improves the last two problems related to code understandability
how use it?
C#’s extension allows you to define a static method that you can invoke using instance method syntax.
1.simply add the this keyword before the argument.
compiling:
1.the compiler first checks if the StringBuilderclass or any of its base classes offers an instance method called IndexOf that takes a single Char parameter.
If an existing instance method exists, then the compiler produces IL code to call it.
If no matching instance method exists, then the compiler will look at any static classes that define static methods called IndexOf that take as their first parameter a type matching the type of the expression being used to invoke the method. This type must also be marked with the this keyword.
question:how does a programmer know that an IndexOf method even exists that can operate on a StringBuilder object?
answer:Microsoft Visual Studio’s IntelliSense feature.
In the editor,when you type a period, Visual Studio’s IntelliSense window opens to show you the list of instance methods that are available.
Well, that IntelliSense window also shows you any extension methods that exist for the type of expression you have to the left of the period.
the icon for an extension method has a down arrow next to it, and the tooltip next to the method indicates that the method is really an extension method.
This is truly awesome because it is now easy to define your own methods to operate on various types of objects and have other programmers discover your methods naturally when using objects of these types.
Rules and Guidelines
1.C# supports extension methods only; it does not offer extension properties, extension events, extension operators, and so on.
2.Extension methods (methods with this before their first argument) must be declared in nongeneric,static classes. However, there is no restriction on the name of the class; you can call it whatever you want. Of course, an extension method must have at least one parameter, and only the first parameter can be marked with the this keyword.
3.The C# compiler looks only for extension methods defined in static classes that are themselves defined at the file scope.
In other words, if you define the static class nested within another class, the C# compiler will emit the following message: error CS1109: Extension method must be defined in a top-level static class; StringBuilderExtensions is a nested class.
4.Because the static classes can have any name you want, it takes the C# compiler time to find extension methods
because it must look at all the file-scope static classes and scan their static methods for a match.
To improve performance and also to avoid considering an extension method that you may not want, the C# compiler requires that you “import” extension methods.
For example, if someone has defined a StringBuilderExtensions class in a Wintellect namespace, then a programmer who wants to have access to this class’s extension methods must put a using Wintellect; directive at the top of his or her source code file.
5.It is possible that multiple static classes could define the same extension method.
If the compiler detects that two or more extension methods exist, then the compiler issues the following message: error CS0121: The call is ambiguous between the following methods or properties: 'StringBuilderExtensions.IndexOf(string, char)' and 'AnotherStringBuilderExtensions.IndexOf(string, char)'.
To fix this error, you must modify your source code.
Specifically, you cannot use the instance method syntax to call this static method anymore;
instead you must now use the static method syntax where you explicitly indicate the name of the static class to explicitly tell the compiler which method you want to invoke.
6.You should use this feature sparingly, because not all programmers are familiar with it.
For example,when you extend a type with an extension method, you are actually extending derived types with this method as well.
Therefore, you should not define an extension method whose first parameter is System.Object, because this method will be callable for all expression types and this will really pollute Visual Studio’s IntelliSense window.
7.There is a potential versioning problem that exists with extension methods.
If, in the future,Microsoft adds an IndexOf instance method to their StringBuilder class with the same prototype as my code is attempting to call, then when I recompile my code, the compiler will bind to Microsoft’s IndexOf instance method instead of my static IndexOf method.
Because of this, my program will experience different behavior.
This versioning problem is another reason why this feature should be used sparingly.
Extending Various Types with Extension Methods
1.because an extension method is really the invocation of a static method, the CLR does not emit code ensuring that the value of the expression used to invoke the method is not null.
2.can define extension methods for interface types
3.Extension methods are the cornerstone of Microsoft’s Language Integrated Query (LINQ) technology.
For a great example of a class that offers many extension methods,see the static System.Linq.Enumerable class and all its static extension methods in the Microsoft .NET Framework SDK documentation.
Every extension method in this class extends either the IEnumerable or IEnumerable<T> interface.
4. extension methods for delegate types
5.extension methods to enumerated types
6.C# compiler allows you to create a delegate that refers to an extension method over an object.
the C# compiler generates IL code to construct an Action delegate.
When creating a delegate, the constructor is passed the method that should be called and is also passed a reference to an object that should be passed to the method’s hidden this parameter.
Normally,when you create a delegate that refers to a static method, the object reference is null because static methods don’t have a this parameter.
However, in this example, the C# compiler generated some special code that creates a delegate that refers to a static method (ShowItems) and the target object of the static method is the reference to the “Jeff” string.
Later, when the delegate is invoked, the CLR will call the static method and will pass to it the reference to the “Jeff” string.
This is a little hacky, but it works great and it feels natural so long as you don’t think about what is happening internally.
The Extension Attribute
In C#, when you mark a static method’s first parameter with the this keyword, the compiler internally applies a custom attribute to the method and this attribute is persisted in the resulting file’s metadata. The attribute is defined in the System.Core.dll assembly
this attribute is applied to the metadata for any static class that contains at least one extension method.
And this attribute is also applied to the metadata for any assembly that contains at least one static class that contains an extension method.
So now, when compiling code that invokes an instance method that doesn’t exist, the compiler can quickly scan all the referenced assemblies to know which ones contain extension methods. Then it can scan only these assemblies for static classes that contain extension methods, and it can scan just the extension methods for potential matches to compile the code as quickly as possible.
相关知识:
The ExtensionAttribute class is defined in the System.Core.dll assembly.
This means that the resulting assembly produced by the compiler will have a reference to System.Core.dll embedded in it even if I do not use any types from System.Core.dll and do not even reference System.Core.dll when compiling my code.
However, this is not too bad a problem because the ExtensionAttribute is used only at compile time;
at run time,System.Core.dll will not have to be loaded unless the application consumes something else in this assembly.
7.Partial Methods
示例:
1.The type must be a class that is not sealed.
You cannot use this technique for sealed classes or for value types (because value types are implicitly sealed).
In addition, you cannot use this technique for static methods because they cannot be overridden.
2.There are efficiency problems here.
A type is being defined just to override a method; this wastes a small amount of system resources.
And, even if you do not want to override the behavior of OnNameChanging, the base class code still invokes a virtual method that simply does nothing but return.
Also, ToUpper is called whether OnNameChanging accesses the argument passed to it or not.
优化:
优点:
1.The class is now sealed (although it doesn’t have to be). In fact, the class could be a static class or even a value type.
2.can rerun the tool and produce new code in a new source code file, but your code remains in a separate file and is unaffected.
And, this technique works for sealed classes, static classes, and value types.
3.Partial methods work similarly to the System.Diagnostics.ConditionalAttribute attribute.
However, partial methods work within a single type only while the ConditionalAttribute can be used to optionally invoke methods defined in another type.
example:you do not need to modify the behavior of the tool-produced type. In this case, you do not supply your source code file at all. If you just compile the tool-produced code by itself, the compiler produces IL code and metadata as if the tool-produced code looked like this.
if there is no implementing partial method declaration, the compiler will not emit any metadata representing the partial method.
In addition, the compiler will not emit any IL instructions to call the partial method.
And the compiler will not emit code that evaluates any arguments that would have been passed to the partial method.
In this example, the compiler will not emit code to call the ToUpper method. T
he result is that there is less metadata/IL, and the run-time performance is awesome!
技巧:
In Visual Studio’s editor, if you type in partial and press the spacebar, the IntelliSense window shows you all the enclosing type’s defined partial method declarations that do not yet have matching implementing partial method declarations.
You can then easily select a partial method from the IntelliSense window and Visual Studio will produce the method prototype for you automatically.
This is a very nice feature that enhances productivity.
Rules and Guidelines
1.They can only be declared within a partial class or struct.
2.Partial methods must always have a return type of void, and they cannot have any parameters marked with the out modifier.
These restrictions are in place because at run time,the method may not exist and so you can’t initialize a variable to what the method might return because the method might not exist.
Similarly, you can’t have an out parameter because the method would have to initialize it and the method might not exist.
A partial method may have ref parameters, may be generic, may be instance or static, and may be marked as unsafe.
3.Of course, the defining partial method declaration and the implementing partial method declaration must have identical signatures.
If both have custom attributes applied to them, then the compiler combines both methods’ attributes together.
Any attributes applied to a parameter are also combined.
4.If there is no implementing partial method declaration, then you cannot have any code that attempts to create a delegate that refers to the partial method. Again, the reason is that the method doesn’t exist at run time. The compiler produces this message: error CS0762: Cannot create delegate from method 'Base.OnNameChanging(string)'
because it is a partial method without an implementing declaration.
5.Partial methods are always considered to be private methods.
However, the C# compiler forbids you from putting the private keyword before the partial method declaration.