Home > Back-end >  How to write into a generic array using a method? Generic array doesn't change datatype after s
How to write into a generic array using a method? Generic array doesn't change datatype after s

Time:11-04

How could I use the method writeArray to write values into the generic array T[]? Compiler gives an error, see the comment in the code.

It seems the generic array is still generic as T. I thought by initializing the intObj with specifying that T is int, every placeholder T in the object is now datatype int? So with this.array[i] where the error happens, I expected T[] to turn to int[]. Thank you in advance.


class GenericArray<T> {
    Random rnd=new Random();
    T[] array = new T[3];
    
    public void writeArray() {
        for (int i = 0; i<this.array.Length; i  ) {
            this.array[i]=rnd.Next(1,10);   //Cannot implicitly convert type 'int' to 'T'
        }
    }
}

class Program {
    public static void Main() {
        GenericArray<int> intObj = new GenericArray<int>();
        
        intObj.writeArray();
        }
}

CodePudding user response:

A class that is generic over T must be able to handle all types of T. That means that writeArray has to work no matter what T was specified. Your version won't work, of course, if T is anything other than a numeric data type, because Random always generates numbers. Hence it's not allowed.

What we need to do is rewrite your class so that it only contains the code that is generic to all T.

abstract class GenericArray<T>
{
    protected T[] array = new T[3];

    protected abstract T GenerateRandomValue();

    public void WriteArray()
    {
        for (int i=0; i<this.array.Length; i  )
        {
            this.array[i] = GenerateRandomValue();
        }
    }
}

This makes sense because we know how to store an array of any T (we declare it), and we know how to loop over an array of any T (we use for), but we don't know how to generate a random value for any T (so we leave that out as abstract).

When you need to include type-specific logic, you can close the type (inherit from it and state the type parameter) and provide the implementation there.

class IntegerArray : GenericArray<int>
{
    Random rnd = new Random();

    protected override int GenerateRandomValue() => rnd.Next(1,10);
}

And of course you can do this for other types. Here it is for a string. Since Random produces numbers, we need to use a different function to get a random string. In this example I just use a GUID.

class StringArray : GenericArray<string>
{
    protected override string GenerateRandomValue() => System.Guid.NewGuid.ToString();
}

Now you can do this in your main program:

var array = new IntegerArray();
array.WriteArray();

CodePudding user response:

Here

this.array[i]=rnd.Next(1,10);

rand.Next() returns an int; it always returns an int, regardless of what you write in your own class that calls Next(). The left-hand operand always has type T. How would compiler know what to do if you passed, for example, a string (as said in comments) or, let's say, a FileStream? How would it guess what kind of result do you expect when assigning an int to be a FileStream?

What you can do is provide a way for your generic class to get an object of type T from int, either on creation or right in WriteArray() method:

class GenericArray<T> 
{
    Random rnd = new Random();
    T[] array = new T[3];
    
    public void WriteArray(Func<int, T> FuncToGetTFromInt) 
    {
        for (int i = 0; i<this.array.Length; i  ) 
        {
            this.array[i] = FuncToGetTFromInt(rnd.Next(1,10));   
        }
    }
}

And you'd use it like that:

Func<int, string> FuncToGetStringFromInt = (value) => 
{
    return $"This int's value was {value.ToString()}";
}; 
intObj.writeArray(FuncToGetStringFromInt);

Or (preferably) you'd provide the whole function that gives random objects of type T:

public void writeRandomArray(Func<T> FuncToGetRandomT) 
{
    for (int i = 0; i<this.array.Length; i  ) 
    {
        this.array[i] = FuncToGetRandomT();   
    }
}

And use it like that:

Random rnd = new Random();

GenericArray<string> aStr = new GenericArray<string>();
Func<string> FuncToGetRandomString = () => {return $"Hello world {rnd.Next()}!";};  
aStr.WriteRandomArray(FuncToGetRandomString);

GenericArray<int> aInt = new GenericArray<int>();
Func<int> FuncToGetRandomInt = () => {return rnd.Next();};
aInt.WriteRandomArray(FuncToGetRandomInt);
  • Related