2

I see that there is a similar question for C++. Does anyone know why this method works when the method is non-generic, but as soon as I make it generic, the random number portion of code fails? Error: Cannot implicitly convert type int to 'T'. If I can't use generics, I will have to rewrite the same function over and over for each different length of array.

public void fillGenericArray<T>(T[] inputArray) where T : IComparable
{
    var randomNumb1 = new Random();

    for (int i = 0; i < inputArray.Length - 1; i++)
    {
        Console.WriteLine($"{inputArray[i] = randomNumb1.Next(1, 501)},");
    }
}
J_W
  • 51
  • 4
  • And what exactly would you expect your code to do with `fillGenericArray(someGuidArray);`? – juharr May 30 '20 at 15:26
  • It generates a random list of 100 ints from 1- 500. For ex, this code works: `public void filloneHundrArray(int[] oneHundredArray) { var randomNumb1 = new Random(); for (int i = 0; i < oneHundredArray.Length - 1; i++) { Console.WriteLine($"{oneHundredArray[i] = randomNumb1.Next(1, 501)},"); } }` – J_W May 30 '20 at 16:03
  • I <3 generics! Great question. – IVSoftware May 30 '20 at 16:34

2 Answers2

2

I had to look twice at this, but here's the issue:

Because inputArray is an 'array of type T'

then even though i is an int the expression

inputArray[i] 

returns a type T not a type int.

And so, conversely, a type T must be assigned to it.

A generic method like this might achieve your goal:

public static void fillGenericArray<T>(T[] inputArray)
{
    for (int i = 0; i < inputArray.Length; i++)
    {
        // Where T has a CTor that takes an int as an argument
        inputArray[i] = (T)Activator.CreateInstance(typeof(T), Random.Next(1, 501));
    }
}

(Thanks to this SO post for refreshing my memory about instantiating T with arguments.)

You could also use Enumerable.Range() to get the same result without writing a method at all:

// Generically, for any 'SomeClass' with a CTor(int value)
SomeClass[] arrayOfT = 
    Enumerable.Range(1, LENGTH).Select(i => new SomeClass(Random.Next(1, 501)))
    .ToArray();

(Slightly Modified with help from this SO post) - see the answer using Enumerable.Range().

Here is a test runner:

class Program
{
    static Random Random { get; } = new Random();
    const int LENGTH = 10;
    static void Main(string[] args)
    {

        Console.WriteLine();
        Console.WriteLine("With a generic you could do this...");


        SomeClass[] arrayOfT;
        arrayOfT = new SomeClass[LENGTH];
        fillGenericArray<SomeClass>(arrayOfT);
        Console.WriteLine(string.Join(Environment.NewLine, arrayOfT.Select(field=>field.Value)));


        Console.WriteLine();
        Console.WriteLine("But perhaps it's redundant, because Enumerable is already Generic!");

        arrayOfT = Enumerable.Range(1, LENGTH).Select(i => new SomeClass(Random.Next(1, 501))).ToArray();
        Console.WriteLine(string.Join(Environment.NewLine, arrayOfT.Select(field => field.Value)));

        // Pause
        Console.WriteLine(Environment.NewLine + "Any key to exit");
        Console.ReadKey();
    }
    public static void fillGenericArray<T>(T[] inputArray)
    {
        for (int i = 0; i < inputArray.Length; i++)
        {
            inputArray[i] = (T)Activator.CreateInstance(typeof(T), Random.Next(1, 501));
        }
    }
    class SomeClass
    {
        public SomeClass(int value)
        {
            Value = value;
        }
        public int Value { get; set; }
    }
}

Console Output

Clone or Download this example from GitHub.

IVSoftware
  • 5,732
  • 2
  • 12
  • 23
  • See [Microsoft Documentation](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1?view=netcore-3.1#examples) for more IEnumerable examples. – IVSoftware May 30 '20 at 16:13
1

There is no reason to use generics. Just replace T with int and you will have function that does what you want (based on your question and comment below it).

EDIT: From your comment it seems you misunderstand the purpose of generics. The non-generic function WILL work for all lengths of the array.

And to answer why the change to generics fails. You are trying to assign int to generic type T which can be anything and compiler will not allow such a cast.

mcc
  • 135
  • 7
  • mcc is correct. If all you want are integer arrays of varying lengths that contain random numbers, use: int[] arrayOfInt = Enumerable.Range(1, LENGTH).Select(i => Random.Next(1, 501)).ToArray() – IVSoftware May 30 '20 at 18:46
  • And btw that is a good inference, mcc, but if this is the case we might ask for the OP question to be reworded to something like "Initializing variable-length arrays with random numbers". I'm not quite sure myself if the essential question is about generics or about that. But kudos either way. – IVSoftware May 30 '20 at 19:11
  • 1
    @IVSoftware yes, either the header or the body of the question should be reworded. I expect the header. – mcc May 30 '20 at 19:15
  • mcc if the word _generic_ gets taken out of the header, I'll upvote _your_ answer :) – IVSoftware May 30 '20 at 19:57