简体   繁体   中英

How to write into a generic array using a method? Generic array doesn't change datatype after specifying the type

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();
        }
}

Putting the writeArray() method inside the GenericArray<T> class doesn't make sense. What is supposed to happen if you initialize an object like GenericArray<string> intObj = new GenericArray<string>();

I suggest either moving the method out of the class or making it static like:

public static GenericArray<int> writeIntArray(){
    Random rnd=new Random();
    GenericArray<int> intObj = new GenericArray<int>();
    for (int i = 0; i < intObj.array.Length; i++) {
        intObj.array[i]=rnd.Next(1,10);
    }
    return intObj;
}

However, you won't be able to call the method directly in the latter case, see . Another question would be if your T type is always a number-type?

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);

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 T 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 T GenerateRandomValue() => System.Guid.NewGuid.ToString();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM