Created Wednesday 08 January 2014
Anonymous Types
You create anonymous types by using the new
operator together with an object initializer:
var anonymousType = new { First = "Uriel", Last = "Avalos" }; Console.WriteLine(v.Amount + v.Message);
Extension Methods
An extension method "adds" new methods to existing types without modifying the original source code. In most cases, you will be using pre-defined extension methods instead of creating your own.
Limitations
- Can only add new methods. If you try to add an extension method with the same signature as an existing method, the existing method will be used.
- Cannot access private data.
Creating an Extension Method
using System.Linq; using System.Text; using System; namespace CustomExtensions { //Extension methods must be defined in a static class public static class StringExtension { // This is the extension method. // The first parameter takes the "this" modifier // and specifies the type for which the method is defined. public static int MyLength(this String str) { return str.Length; } } } namespace Extension_Methods_Simple { //Import the extension method namespace. using CustomExtensions; class Program { static void Main(string[] args) { string s = "The quick brown fox jumped over the lazy dog."; // Call the method as if it were an // instance method on the type. Note that the first // parameter is not specified by the calling code. int i = s.MyLength(); } } }
- See also ExtensionMethods
Delegates
A delegate is a function pointer. Unlike function pointers in C or C++, delegates are object-oriented, type-safe, and secure.
Creating a Delegate
//declare delegate delegate void foobar(int i); class Foo { //assign these two as delegates implementing foobar public void delegate1(int i) { //... } public void delegate2(int i) { //... } //pass delegate as function pointer to method public callDelegate(foobar delegateMethod) { //call delegate with input 0 delegateMethod(0); } } Foo foo = new Foo(); //create delegates foobar delegate1 = new foobar(foo.delegate1); foobar delegate2 = new foobar(foo.delegate2); //invoke delegates directly delegate1(1000); //pass delegate to fuction foo.callDelegate(delegate1); //NOTE: you can also do chain delegates together! foobar delegate3 = delegate1 + delegate2; //calls delegate1 followed by delegate2 delegate3(100);
Delegates vs Interfaces
With the exception of the neat function chaining shown above, you can get the same functionality by using an interface. In fact, in Java, that's the technique that's used to get function-pointer-like behavior. For example:
//declare interface to use as "function pointer" interface IFunctionPtr { void method(); } //function to use as "function pointer" public void functionPtr() { //... } //accepts "function pointer" as param public void callFunctionPtr(IFunctionPtr ptr) { //call "function pointer" interface ptr.method(); } //create "function pointer" IFunctionPtr javaFunctionPtr = new IFunctionPtr() { @Override public void method() { functionPtr(); } }; //invoke "function pointer" directly javaFunctionPtr.method(); //pass "function pointer" to function callFunctionPtr(javaFunctionPtr);
Unfortunately, other than the neat function chaining described earlier, I don't see any reason to use a delegate except to get more compact code (you don't have to wrap the method with an anonymous class).
Note that there are times when it does not make sense to use a delegate:
- You'll call a set of related methods
- You need access to the object the method is defined on. Ex: The caller of the interface wants to cast to or from the interface type to obtain other interfaces or classes.
Inheritance
In Java, methods are virtual by default. You make them non-virtual with the final
keyword. In C#, methods are not virtual by default. You must explicitly make them virtual with the virtual
keyword. (See the override
/virtual
keywords in :CSharp:MigratingFromJava1.)
An explanation via code:
class Base { public void method1() { //... } } Base base = new Base(); Derived derived = new Derived(); //extends base Base bd = new Derived(); | | Java | C# | |-------------------|-----------------------|-----------------------| | base.method1() | calls Base#method1 | calls Base#method1 | | derived.method1() | calls Derived#method1 | calls Derived#method1 | | bd.method1() | calls Derived#method1 | calls Base#method1 | //in Java, by default, polymorphism (which is slow) kicks in //in C#, you must explicitly enable polymorphism
Events
C# has built-in support for events.
Creating and Using Events
//Define delegate callback public delegate boolean ChangedEventHandler(object sender, int i); class EventClass { //clients register listener with this event public event ChangeEventHandler changedEvent; public void foo() { //invoke event if (changedEvent != null) { if (changedEvent(this, 50)) //...; else //....; } } class Test { //onChange handler private boolean onChanged(object sender, int i) { //... } public void bar() { EventClass eventClass = new EventClass(); //register event handler //"+=" notation means you can add multiple handlers eventClass.changedEvent += new ChangedEventHandler(onChanged); eventClass.foo(); //calls Test#onChanged //unregister event handler
eventClass.changedEvent -= new ChangedEventHandler(onChanged);
}
}
Note: C# provides a built-in delegate for handling events EventHandler
which is defined as
public delegate void EventHandler(object sender, EventArgs e);
where EventArgs
is a built-in class.
Events and Inheritance
- child classes cannot directly invoke an event from a parent class. The workaround is to define a
virtual
parent method that calls the event directly. Child classes can thenoverride
this method. - events can be defined in interfaces. Implementing classes must define a corresponding event.
Working with EventHandler Class, Creating Events That Work With .NET Framework
See How to: Publish Events that Conform to .NET Framework Guidelines
Lambdas
A lambda expression are anonymous functions that can be used to create delegates or expression trees.
Creating a Lambda
//first define a delegate delegate int foo(int i); delegate int bar(int a, int b); delegate int foobar(); //... //these are all equivalent: foo lambda1 = (x) => x * x; foo lambda2 = x => x * x; foo lambda3 = (int x) => x * x; foo lambda4 = x => { Console.WriteLine(x); return x * x; }; //multi-statement //multi-params: bar lambda1b = (x,y) => x + y; bar lambda2b = (int x, int y) => x + y; //no params: foobar lambda1c = () => 4; //returns 4 (DOH!) //in general, //(input params) => expression (returning a value)
Note 1: You don't need to specify the type of the input params (like in the examples above). However, the arguments must implicitly cast to the types defined in the delegate.
Note 2: Multi-statement lambdas are called statement lambdas and they are not supported by LINQ expression providers.
Lambdas and Closure
Like Javascript, you can reference outside variables inside of a lambda expression (thereby, creating a closure). And like Javascript, the same issues related to closure apply. For example:
delegate int foo(); foo[] foos = new foo[5]; for (int i=0; i<5; i++) { foos[i] = x => i; } //does NOT print 0,1,2,3,4 //instead prints 5,5,5,5,5 for (int i=0; i<5; i++) Console.WriteLine(foos[i]());
Anonymous Methods vs Lambdas
C# 2.0 introduced anynymous methods and C# 3.0 introduced lambdas. As per the offical docs, lambdas are the preffered way to write inline code.
Creating an Anonymous Method
// Create a delegate. delegate void foo(int x); // create the anonymous method foo d = delegate(int k) { // ... };
Unsafe Mode
Unsafe mode is for allowing C/C++ style pointer manipulation. The following are the recommended reasons for using unsafe mode:
- Performance-critical code
- Dealing with existing structures on disk
- Advanced COM or Platform Invoke scenarios that involve structures with pointers in them
Note: With pointers you get better performance than the usual array access; however, the resulting code is harder to maintain. Do NOT use unsafe mode just to write C/C++ code in C#!
See the resources below for more information.
Resources
- Delegates
- ExtensionMethods
- All about delegates
- Events Tutorial
- How to Publish Events that Conform to .NET Guidelines
- Lambda Expressions
- Expression Lambda versus Statement Lambda
- Unsafe Code Tutorial
- Anonymous Types