Unlike templates in C++, you can't use generics to call a language defined operator. This is rather annoying because it's the first thing that anyone tries, and what's more the base numeric types don't implement an INumeric interface or anything that would provide a workaround.
Here's as simple an example of a constraint as I can come up with:
class Combiner<T> where T: ICombinable {
public T Combine(T a, T b) { return a.Combine(b); }
}
interface ICombinable {
object Value { get; }
ICombinable Combine(ICombinable b);
}
class Combinable : ICombinable {
public object Value { get; set; }
public Combinable(object value) { Value = value; }
public ICombinable Combine(ICombinable other) {
ArrayList al = new ArrayList();
al.Add(Value);
al.Add(other.Value);
return new Combinable(al);
}
}
class Starter {
static void Main(){
Combinable one = new Combinable(1), two = new Combinable(2);
var combiner = new Combiner<Combinable>();
Combinable result = combiner.Combine(one, two);
Console.WriteLine(result.Value);
}
}
Without the bolded constraint in the definition of Combiner<T>, you couldn't use any methods on T within that dlass (beyond the standard methods on object, i.e. GetHashCode, ToString etc). The constraint means that you can only set the type parameter to something that implements the interface you put there, e.g. Combiner<int> would be an error because int doesn't implement ICombinable, and therefore you can safely use ICombinable methods (i.e. Combine) within the Combiner<T>.
The rest of the code is just defining some code that actually does something so you can make a runnable example of it, I've deliberately stayed away from generics except for the very simple Combiner class with a constraint on it.