Monday, April 11, 2011

Operator Overloading For Builtin Types

Hi, How can I override operators to be used on builtin types like String, arrays etc? For example: I wish to override the meaining of the + operator for arrays.

From stackoverflow
  • Basically you can't.

    You can use extension methods to add functionality like this:

    public void CustomAdd( this Array input, Array addTo ) {
        ...
    }
    

    But this doesn't work with operators.

    Lennie : Shouldn't use operator overloading on builtin types or extension methods?
    Keith : Yes - even if you could do this it would result in very confusing code: "why does this array not work like they normally do?"
  • You can't :)

    You can however for the array example inherit from an IEnnumerable or List ... and override those operators.

  • The short answer is that you can't, as @Keith pointed out.

    The longer answer is that for you to add operator overloading to a class, you need to be able to change the source code for that class.

    In the case where an operator is added to handle the combination of two distinct types (array + string for instance), it is enough that you can change the source code for one of those types. This means that you should be able to add code to specify what happens if you add one of your own types to an array.

    In the case of BCL classes, you're out of luck though.

  • You can't overload operators for existing types, as that could potentially break any other code that uses the types.

    You can make your own class that encapsulates an array, expose the methods and properties that you need from the array, and overload any operators that makes sense.

    Example:

    public class AddableArray<T> : IEnumerable<T> {
    
     private T[] _array;
    
     public AddableArray(int len) {
      _array = new T[len];
     }
    
     public AddableArray(params T[] values) : this((IEnumerable<T>)values) {}
    
     public AddableArray(IEnumerable<T> values) {
      int len;
      if (values is ICollection<T>) {
       len = ((ICollection<T>)values).Count;
      } else {
       len = values.Count();
      }
      _array = new T[len];
      int pos = 0;
      foreach (T value in values) {
       _array[pos] = value;
       pos++;
      }
     }
    
     public int Length { get { return _array.Length; } }
    
     public T this[int index] {
      get { return _array[index]; }
      set { _array[index] = value; }
     }
    
     public static AddableArray<T> operator +(AddableArray<T> a1, AddableArray<T> a2) {
      int len1 = a1.Length;
      int len2 = a2.Length;
      AddableArray<T> result = new AddableArray<T>(len1 + len2);
      for (int i = 0; i < len1; i++) {
       result[i] = a1[i];
      }
      for (int i = 0; i < len2; i++) {
       result[len1 + i] = a2[i];
      }
      return result;
     }
    
     public IEnumerator<T> GetEnumerator() {
      foreach (T value in _array) {
       yield return value;
      }
     }
    
     IEnumerator System.Collections.IEnumerable.GetEnumerator() {
      return _array.GetEnumerator();
     }
    
    }
    

    Usage:

    // create two arrays
    AddableArray<int> a1 = new AddableArray<int>(1, 2, 3);
    AddableArray<int> a2 = new AddableArray<int>(4, 5, 6);
    
    // add them
    AddableArray<int> result = a1 + a2;
    
    // display the result
    Console.WriteLine(string.Join(", ", result.Select(n=>n.ToString()).ToArray()));
    

    (Note that as the class implements IEnumerable<T>, you can use extension methods like Select on it.)

    Keith : That's a lot code just so that a1 + a2 = unified array. Why not just do a1.Union(a2).ToArray()
    Guffa : Yes, that is a lot simpler, but it's not as efficient. It's fairly good though, a quick test shows that it only takes about 2-4 times longer.

0 comments:

Post a Comment