Click here to Skip to main content
15,902,904 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
hello everyone the following code is my attempt to create a generic class in C#
the idea is to create an Array of elements of the same type
the problem i ran into is when try trying to calculate the sum of the element in an array , generic classes in c# doesn't allow me to do arithmetics
any help please

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Devoire
{
    class Tableau<T>
    {
        private T[] tab;
        int cnt;

        public Tableau(int ss = 0)
        {
            tab = new T[ss];
            cnt = 0;
        }
        public Tableau(T[] ar, int count)
        {
            if (count > ar.Length)
                count = ar.Length;
            tab = new T[count];
            for (int i = 0; i < count; i++)
            {
                if (ar[i] != null)
                {
                    tab[i] = ar[i];
                    cnt++;
                }
            }
            
        }

        public T this[int index]
        {
            get {
                if( index < cnt)
                {
                    return tab[index];
                }
                else
                {
                    return default(T);
                }
            }
            set
            {

                    if (index >= cnt)
                    {
                        index = cnt++;
                    }
                    if (cnt > tab.Length)
                    {
                        T[] newtab = new T[cnt];
                        Array.Copy(tab, newtab, index);
                        tab = newtab;
                    }

                    tab[index] = value;

            }
        }
        public  static Tableau<T>   fusionner(Tableau<T> tabl, Tableau<T> tab2)
        {
            Tableau<T> tmp = new Tableau<T>(tabl.cnt + tab2.cnt);
            for(int i = 0 ; i < tabl.cnt ; i++)
            {
                tmp[i] = tabl[i];
            }
            for (int i = tabl.cnt , j = 0 ; i < tmp.taille; i++)
            {
                tmp[i] = tab2[j++];
            }
            return tmp;
            
        }
        public int taille
        {
            get
            {
                return tab.Length;
            }
        }
        public T Premier
        {
            get
            {
                return tab[0];
            }
            set
            {
                tab[0] = value;
                if (cnt == 0)
                    cnt++;
                             
            }
        }
        public override string ToString()
        {
            string s = "" ;
            for (int i = 0 ;  i < cnt ; i++)
            {

                s += tab[i] + " ";
            }
            return s;
        }
        public  Tableau<T> copie(Tableau<T> tabl)
        {
            cnt = tabl.cnt;
            tab = new T[cnt];
            for (int i = 0; i <cnt; i++ )
            {
                tab[i] = tabl[i];
            }
            return this;
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
           
            double[] ar = { 1.2, 125.3, 3.3, 4, 10.3, 11, 12 };
            int[] ar1 = { 1, 125, 3, 4, 10, 11, 12 };
            int a = ar.Length;
            Tableau<double> tb = new Tableau<double>(ar,3);
            Tableau<int> tb2 = new Tableau<int>(ar1, 4);

            Tableau<int> tb3 = new Tableau<int>(15);
            tb3.Premier = 6;
            tb3.Premier = tb3.Premier *  (int)tb.Premier;
            Console.WriteLine(tb3);
        }
    }
}


What I have tried:

i search for a solution online but i didn't understand most of them
any help would great
thank you
Posted
Updated 30-May-16 12:02pm
Comments
Philippe Mori 30-May-16 17:43pm    
Generics are quite limited in .NET (compared to say templates in C++).

One could use some tricks like those proposed in solutions but for code like this (matrix operations), you might have an undesirable impact on performance (or the code might be too complex).

Thus, in the end, there is no easy way to do that and hard way might not be adequate anyway for problem like this one.

In a case like this, one would probably only write the double version in C# and possibly some conversion function from/to narrower types.

Indeed, as it is explained in Solution 2, is an interesting problem. Unfortunately, it does not have a perfect solution.
Please see my past answer:
Generics in C#: compile-time error, '+' cannot be applied[^],
Generic constraints on methods[^].

See also my comment to Solution 2.

—SA
 
Share this answer
 
v3
Generics can't do arithmetic because not all classes support all the operations required. For example, while you can subtract two DateTime values to get a Timespan, what on earth would you get by adding them together? :laugh:
Because not all possible classes that could be the "target" of the generic support the operators, you can't use them on any generic type without explicitly casting them.
The exception is when you use a constraint on the type of the generic:
C#
private class myClass<T> where T : baseClass
    {
But...you can't use any constraint in this case, as int, double and so forth are structs, not classes and as such are implicitly sealed - a type constraint must be a derivable class.

Sorry - but you can't do what you want via generics!
 
Share this answer
 
Comments
Member 12223678 30-May-16 14:31pm    
thank you @OriginalGriff
maybe Microsoft will come up with a solution in the future
OriginalGriff 30-May-16 14:38pm    
No, probably not.
It's not a "solvable" problem: it's a prerequisite of the way C# (and the whole of .NET) works. If the base class doesn't support an operation then it's derived classes don't have to either. And if it let you through now (because you "know" that all the classes you are going to use with the Generic do support add, subtract, multiply, and divide) then in a months time what happens when you use the class as part of an assembly, and pass it a DateTime? Your app crashes at runtime for an error that should have been caught at compile time!
As a result, the safe way to do it is to prevent your code compiling unless all applicable classes have to implement every method you are going to use on them.
Very, very unlikely to change!
Interesting question.

Since not all types support arithmetics and there is no generic operator support in .NET you must inject a type-specific operator into your generic Tableau class.

To add support for addition you can add a delegate variable to your generic class like this
C#
public static Func<t,t,t> Addition;

which you then can invoke from a Sum function like this
C#
public T Sum()
{
    T sum = default(T);
    for (int i = 0; i < cnt; i++)
    {
       sum = Addition(sum, tab[i]);
    }
    return sum;
} 

Before using this method you must "teach" the class how to add the types you want to use by simply assigning the Addition function once
C#
Tableau<int>.Addition = (a,b) => a+b;
Tableau<string>.Addition = (a,b) => a+b;</string></int>

for each type that you want to use.

I think this idea can be generalized (and improved by some encapsulation). If anyone finds it useful I may present in an article here.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 30-May-16 18:08pm    
I voted 4. Basically, you are right, but there is one more accurate pretty known solution.
You need to define and interface defining numeric arithmetic, more or less limited. And then you need to implement this interface for each of the numeric types to be used as a generic parameter.

The generic type need two generic parameters: the numeric type and associated arithmetic type, which can be constrained by this interface. These two type should match; and it's impossible to constraint. The solution is ugly, but I believe that there is no a better choice with present-day .NET.

I failed to find an original article where I got the idea, so I wrote some illustration code. Please see Solution 3.

—SA
Member 12223678 31-May-16 16:52pm    
hello @Henrik Jonsson
first thank you for your answer it was very helpful,
if it's possible could you please explain in detail this delegate variable
public static Func<t, t,="" t=""> Addition;
i didn't understand it quite well

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900