Generics Problem in Operators  
Author Message
Gaurav G





PostPosted: Visual C# Language, Generics Problem in Operators Top

Hi ,

I am trying to design a Generic Method which can add any type of data.

while i am compiling it is giving following error:

2 Operator '+' cannot be applied to operands of type 'T' and 'T'

Following is the code:

Please help

using System;

using System.Collections.Generic;

using System.Text;

namespace GenericsConsoleApplication

{

class Program

{

static void Main(string[] args)

{

}

}

class GenericClass1<T>

{

public T result;

public T Add<T>(T vara, T varb)

{

return result = vara + varb;

}

}

}




Visual C#8  
 
 
Lepaca





PostPosted: Visual C# Language, Generics Problem in Operators Top

Compiler don't know T type... You have to do some conversions...

public T result;
public T Add<T>(T vara, T varb)
{
    Type ty = typeof(T);
    Object a = vara;
    Object = varb;

    If (ty = typeof(Integer))
    {
        Return (T)((Object)((Integer)a + (Integer)b));
    }
    Else If (ty = typeof(Double))
    {
        Return (T)((Object)((Double)a + (Double)b));
    }
    Else
    {
        [RAISE an Exception!!!]
    }
}


 
 
Sagitt





PostPosted: Visual C# Language, Generics Problem in Operators Top

The problem you are having is because the compiler needs to know at compile time that any type you create the generic class with knows how to apply the + operator and the way you have it coded tells the compiler that T can be absolutely any type but not all types define how to use + with itself. In other words, if T were an int then the compiler could handle it because it know how to add integers, if T were a string then it knows how to concatenate strings. But if T is of type Car and Car does not have a method for '+'-ing two Car objects, then the compiler has no idea what to do with that.

You need to add a constraint on your generic type to tell the compiler that whatever type T is it will have the + operator define on two objects of T type. Refer to the following MSDN Programmers reference for more info on constraining a generic: http://msdn2.microsoft.com/en-us/library/d5x73970.aspx


 
 
Gaurav G





PostPosted: Visual C# Language, Generics Problem in Operators Top

But operator constraints are not supported by c# 2005.

Is there any solution.



 
 
RizwanSharp





PostPosted: Visual C# Language, Generics Problem in Operators Top

But operator constraints are not supported by c# 2005.

Is there any solution.

Compiler doesnot know what T represents It may be an object of Class Employee, then how they'll be added at runtime So the solution is what "Lepaca" has suggested...

Best Regards,

Rizwan



 
 
James Curran





PostPosted: Visual C# Language, Generics Problem in Operators Top

If (ty = typeof(Integer))
{
Return (T)((Object)((Integer)a + (Integer)b));
}

Ick!

IckIckIckIck!

If you are going to to that, you might as well just use overloading:


public int Add(int vara, int varb)
{
return vara + varb;
}

public double Add(double vara, double varb)
{
return vara + varb;
}

I cannot see any advantage of your code over this.



 
 
Lepaca





PostPosted: Visual C# Language, Generics Problem in Operators Top

If (ty = typeof(Integer))
{
Return (T)((Object)((Integer)a + (Integer)b));
}

Ick!

IckIckIckIck!



A little complicated... I know...
But if he want generics...

 
 
louthy





PostPosted: Visual C# Language, Generics Problem in Operators Top

Out of interest, why are you trying to implement an Add method for two objects of the same type

Surely you should just use the default add operator   If not then I suspect you're looking to add extra functionality to the add process.  In which case using inheritance is the way forwards, as mentioned previously in this thread. 

I also suspect that you may actually want to add two objects of differing types, as the original question does seem rather pointless.  If so, then using a base Variable class, subclassed implementations for specfic types, and double-despatching to provide conversions and assignments is the way forwards.  Here's some code I wrote as example:

using System;
using System.Collections.Generic;
using System.Text;

namespace DoubleDespatch
{
 class Program
 {
  static void Main(string[] args)
  {
   Variable a = new IntegerVariable(100);
   Variable b = new IntegerVariable(200);
   Variable c = a.Add(b);

   Console.WriteLine("a + b = {0}", c.Value);

   Variable d = new StringVariable("Fred ");
   Variable e = new StringVariable("Bloggs");
   Variable f = d.Add(e);

   Console.WriteLine("d + e = {0}", f.Value);

   Variable g = new StringVariable("House number: ");
   Variable h = new IntegerVariable(10);
   Variable i = g.Add(h);

   Console.WriteLine("g + h = {0}", i.Value);

  }

 public abstract class Variable
 {
  public abstract Variable Add(Variable rhs);

  public abstract object Value
  {
   get;
  }

  public virtual Variable DespatchAdd(Variable lhs)
  {
   throw new Exception("Can't add variable types of " + lhs.GetType().ToString() + " and " + this.GetType());
  }
  public virtual Variable DespatchAdd(StringVariable lhs)
  {
   throw new Exception("Can't add variable types of " + lhs.GetType().ToString() + " and " + this.GetType());
  }
  public virtual Variable DespatchAdd(IntegerVariable lhs)
  {
   throw new Exception("Can't add variable types of " + lhs.GetType().ToString() + " and " + this.GetType());
  }
 }

 public class StringVariable : Variable
 {
  string value;

  public StringVariable(string value)
  {
   this.value = value;
  }

  public override object Value
  {
   get
   {
    return value;
   }
  }

  public override Variable Add(Variable rhs)
  {
   return rhs.DespatchAdd(this);
  }

  public override Variable DespatchAdd(StringVariable lhs)
  {
   return new StringVariable(lhs.value + value);
  }

  public override Variable DespatchAdd(IntegerVariable lhs)
  {
   return new IntegerVariable(Convert.ToInt32(lhs.Value) + Convert.ToInt32(value));
  }
 }


 public class IntegerVariable : Variable
 {
  int value;

  public IntegerVariable(int value)
  {
   this.value = value;
  }

  public override object Value
  {
   get
   {
    return value;
   }
  }

  public override Variable Add(Variable rhs)
  {
   return rhs.DespatchAdd(this);
  }

  public override Variable DespatchAdd(IntegerVariable lhs)
  {
   return new IntegerVariable(lhs.value + value);
  }

  public override Variable DespatchAdd(StringVariable lhs)
  {
   return new StringVariable(lhs.Value.ToString() + value.ToString());
  }
 }
}

Notice how the Add method passes the responsibility for the addition onto the parameter Variable, in turn sending itself as a parameter (which is strongly typed).  You might think using a switch statement would be easier, but once you start adding extra variable types, and extra conversion methods you soon realise this is the way to go.

Paul