如何使用方法写入通用数组?指定类型后,通用数组不会更改数据类型
Posted
技术标签:
【中文标题】如何使用方法写入通用数组?指定类型后,通用数组不会更改数据类型【英文标题】:How to write into a generic array using a method? Generic array doesn't change datatype after specifying the type 【发布时间】:2021-11-03 17:02:34 【问题描述】:如何使用 writeArray 方法将值写入通用数组 T[]?编译器报错,见代码中的注释。
似乎泛型数组仍然像 T 一样泛型。 我想通过指定 T 是 int 来初始化 intObj,对象中的每个占位符 T 现在都是数据类型 int?因此,对于发生错误的 this.array[i],我希望 T[] 变为 int[]。提前谢谢你。
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();
【问题讨论】:
如果我做了new GenericArray<string>().writeArray();
会怎样?听起来你根本不需要泛型。
这对我来说只是泛型工作原理的练习。使用 GenericArraynew GenericArray<string>().writeArray();
会发生什么。它应该是一种教学设备,而不应该修复您的代码。请记住,T
作为泛型类型参数可以是任何东西,那么在 GenericArray<string>
对象上调用 writeArray
是否有意义?现在你明白为什么你的代码不能编译了吗?
对不起,我一定是错过了一些重要的知识,因为我真的什么都想不起来。也许使用GenericArray<string>
方法writeArray
也不能将随机数从int 转换为字符串?而且编译器只是没有说“不能从int转换为字符串”而是“int to T”?
没错。 T
不一定是 int
,对吧?如果它恰好是string
,那么rnd.Next
返回的整数就不再是正确的类型了!编译器必须能够证明您的代码在所有情况下都是类型安全的。这就是它尝试将int
转换为T
的原因。您可以放入数组的唯一类型是T
- 所有其他类型在某些 情况下都会失败。如果你输入了int
,那么如果T
变成string
就行不通了。
【参考方案1】:
泛型于T
的类必须能够处理所有类型的T
。这意味着无论指定什么 T
,writeArray
都必须工作。当然,如果T
不是数字数据类型,您的版本将无法工作,因为Random
总是生成数字。因此,这是不允许的。
我们需要做的是重写你的类,使它只包含对所有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();
这是有道理的,因为我们知道如何存储任何T
的数组(我们声明它),并且我们知道如何循环任何T
的数组(我们使用for
),但我们不知道'不知道如何为任何T
生成随机值(因此我们将其保留为abstract
)。
当您需要包含特定于类型的逻辑时,您可以关闭类型(从它继承并声明类型参数)并在那里提供实现。
class IntegerArray : GenericArray<int>
Random rnd = new Random();
protected override int GenerateRandomValue() => rnd.Next(1,10);
当然,您也可以对其他类型执行此操作。这是一个字符串。由于Random
产生数字,我们需要使用不同的函数来获取随机字符串。在此示例中,我只使用 GUID。
class StringArray : GenericArray<string>
protected override string GenerateRandomValue() => System.Guid.NewGuid.ToString();
为了强调重点,这里还有一个使用复杂类型的示例 T
。
class PointArray : GenericArray<Point>
Random rnd = new Random();
protected override Point GenerateRandomValue() => new Point(rnd.Next(0,100), rnd.Next(0,100));
现在您可以在主程序中执行此操作:
var array = new IntegerArray();
array.WriteArray();
【讨论】:
我一定是做错了什么。protected override T GenerateRandomValue() => rnd.Next(1,10);
给了我错误 type or namespace name 'T' could not be found
和 'IntegerArray.GenerateRandomValue()': return type must be 'int' to match overridden member 'GenericArray<int>.GenerateRandomValue()'.
由于 IntergerArray 继承自 GenericArrayT
不再存在并且不能被GenerateRandomValue()
使用这里
this.array[i]=rnd.Next(1,10);
rand.Next()
返回一个整数;无论您在自己的调用Next()
的类中编写什么,它总是返回一个int。左侧操作数的类型始终为T
。例如,如果您传递了 string
(如 cmets 中所述)或 FileStream
,编译器将如何知道该怎么做?将int
分配为FileStream
时,它会如何猜测您期望得到什么样的结果?
您可以做的是为您的泛型类提供一种从 int 获取 T 类型对象的方法,无论是在创建时还是在 WriteArray()
方法中:
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));
你会这样使用它:
Func<int, string> FuncToGetStringFromInt = (value) =>
return $"This int's value was value.ToString()";
;
intObj.writeArray(FuncToGetStringFromInt);
或者(最好)你会提供提供 T 类型随机对象的整个函数:
public void writeRandomArray(Func<T> FuncToGetRandomT)
for (int i = 0; i<this.array.Length; i++)
this.array[i] = FuncToGetRandomT();
然后像这样使用它:
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);
【讨论】:
以上是关于如何使用方法写入通用数组?指定类型后,通用数组不会更改数据类型的主要内容,如果未能解决你的问题,请参考以下文章