C# 3.0 introduce una interessante feature denominata extension method (vedi C# 3.0 Specification per maggiori dettagli) che in sostanza permette di "agganciare" metodi a qualunque tipo senza dover creare una classe derivata. Il tutto senza penalizzazioni in termini di performance visto che il lavoro è svolto a tempo di compilazione.
Supponiamo ad es. di voler mettere a disposizione di ogni oggetto un metodo Serialize che effettua la serializzazione dello stesso utilizzando System.Xml.Serialization.XmlSerializer. Potremmo scrivere un extension method del tipo:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml.Serialization;

namespace System.Xml.Serialization
{
  
public static class SerializationExtensions
  
{
     
public static void Serialize(this object obj, TextWriter writer)
     
{
        
XmlSerializer s = new XmlSerializer(obj.GetType());
        
s.Serialize(writer, obj);
      
}
  
}
}

// ...

public class Person
{
  
public string FirstName, LastName;
}

Person p = new Person { FirstName = "Mario", LastName = "Rossi" };
p.Serialize(Console.Out);

Per poter disporre del metodo Serialize per ogni oggetto è sufficiente importare il namespace System.Xml.Serialization!
Ovviamente gli extension method funzionano con qualunque tipo, quindi: delegate, System.ValueType, ...
Facciamo un altro esempio: supponiamo di voler fare in modo che per ogni oggetto sia possibile agganciare, a tempo di esecuzione, delle "dynamic property" e quindi poter scrivere una cosa del tipo:

object o1 = new object();
o1.SetProperty("Name", "Mario Rossi");
Console.WriteLine(o1.GetProperty("Name", ""));  

Per fare questo è sufficiente scrivere una classe con un po' di extension method:

public static class DynamicObjectExtensions
{
  
private static Dictionary<object, Dictionary<string, object>> properties = new Dictionary<object, Dictionary<string, object>>();

   public static void SetProperty(this object obj, string name, object value)
   {
     
Dictionary<string, object> tmp;

      if (!properties.TryGetValue(obj, out tmp))
     
{
        
tmp = new Dictionary<string, object>();
        
properties[obj] = tmp;
     
}

      tmp[name] = value;
  
}

   public static T GetProperty<T>(this object obj, string name, T defaultValue)
  
{
     
Dictionary<string, object> tmp;
     
object value;

      if (properties.TryGetValue(obj, out tmp))
     
{
        
if (tmp.TryGetValue(name, out value))
           
return (T)Convert.ChangeType(value, typeof(T));
        
else
           
return defaultValue;
     
}
     
else
        
return defaultValue;
   }
}

Sulla stessa falsa riga sarebbe possibile aggiungere i metodhi HasProperty, RemoveProperty, ...