Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to simulate Java generic wildcards in C#

The following Java code compares the average of two arrays, one of Integers and one of Doubles.

class Generic_Class<T extends Number>
{
    T[] nums; // array of Number or subclass

    Generic_Class(T[] o)
    {
        nums = o;
    }

    // Return type double in all cases.
    double average()
    {
        double sum = 0.0;

        for(int i=0; i < nums.length; i++)
            sum += nums[i].doubleValue();

        return sum / nums.length;
    }


//  boolean sameAvg(Generic_Class<T> ob)
//  Using Generic_Class<T> i get the error:
//  incompatible types: Generic_Class<Double> cannot be converted to Generic_Class<Integer>

//  Using wilcards I get no error
    boolean sameAvg(Generic_Class<?> ob)
    {
        if(average() == ob.average())
            return true;
        return false;
    }
}

The main method is like this:

public static void main(String args[])
{
    Integer inums[] = { 1, 2, 3, 4, 5 };
    Double  dnums[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };

    Generic_Class<Integer> iob = new Generic_Class<Integer>(inums);
    Generic_Class<Double>  dob = new Generic_Class<Double>(dnums);

    System.out.println("iob average is " + iob.average());
    System.out.println("dob average is " + dob.average());

    if (iob.sameAvg(dob))
        System.out.println("Averages of iob and dob are the same.");
    else
        System.out.println("Averages of iob and dob differ.");
}

The result is:

iob average is 3.0
dob average is 3.0
Averages of iob and dob are the same.

I've tried to do the same in C# but, since I have no wildcards, I can't accomplish the same task.

How can I do the same with C# ?

Thank you.

like image 230
user9559069 Avatar asked Feb 13 '26 18:02

user9559069


2 Answers

As other answerers have said, there is no equivalent of Number in C#. The best you can get is struct, IConvertible. However, there is another way of doing the generic wildcard.

Just use another generic parameter:

public class Generic_Class<T> where T : struct, IConvertible
{
    T[] nums;
    public Generic_Class(T[] o)
    {
        nums = o;
    }

    public double Average()
    {
        double sum = 0.0;
        for(int i=0; i < nums.Length; i++)
            sum += nums[i].ToDouble(null);
        return sum / nums.Length;
    }

    // this is the important bit
    public bool SameAvg<U>(Generic_Class<U> ob) where U : struct, IConvertible
    {
        if(Average() == ob.Average())
            return true;
        return false;
    }
}
like image 143
Sweeper Avatar answered Feb 15 '26 07:02

Sweeper


Taking the average of a sequence of numbers is built-in to C#:

var iNums = new int[] { 1, 2, 3, 4, 5 };
var dNums = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0 };

var iAvg = iNums.Average();
var dAvg = dNums.Average();
var areEqual = iAvg == dAvg;

areEqual == true after running the above.

You can even do this with complex types using the Average overload that takes a Func<TSource, T> to return a value:

public class MyValue
{
    private static Random rnd = new Random();

    public int SomeInt { get; set; } = rnd.Next();
}

var myObjArray = new MyValue[] { new MyValue(), new MyValue(), new MyValue(), new MyValue() };

var myAvg = myObjArray.Average(o => o.SomeInt);

So no, wildcards are not available in C#, but using Generics you can simulate wildcards by having multiple overloads of the Func in this case.

See IEnumerable Methods

like image 43
Ron Beyer Avatar answered Feb 15 '26 06:02

Ron Beyer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!