在构造函数参数中使用泛型数组激活泛型类型的问题
Issue activating a generic type with generic array in constructor parameters
我对以下代码有一个非常奇怪的问题:
using System;
using System.Linq;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
var testTuples1 = GimeStringTuples("foo", "bar");
var testTuples2 = GimeTuples("foo", "bar");
Console.ReadKey();
}
public static object GimeStringTuples(params string[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(string)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
return Activator.CreateInstance(specificType, values);
}
public static object GimeTuples<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
dynamic result;
string[] testArgs = { "foo", "bar" };
result = Activator.CreateInstance(specificType, testArgs);
result = Activator.CreateInstance(specificType, values);
return result;
}
}
}
它在倒数第二行失败:
result = Activator.CreateInstance(specificType, values);
这很奇怪,因为它与之前执行的行基本相同:
result = Activator.CreateInstance(specificType, testArgs);
在这两种情况下,相同的参数作为 specificType
参数传递,string[2]
作为第二个参数传递。
而且 GimeStringTuples
方法工作得很好......虽然那里没有涉及泛型 - 这可能是提示。
谁能解释这种不寻常的行为?
我可以告诉你发生了什么。查看生成的程序集,您可以看到编译器引入了一个 object[]
包装 values
参数:
Activator.CreateInstance(specificType, new string[] { "foo", "bar" });
Activator.CreateInstance(specificType, new object[] { values });
现在找不到正确的重载了。
如果您添加演员表,您将获得预期的结果并且代码再次运行:
Activator.CreateInstance(specificType, values as string[])
但我不能告诉你为什么会这样,也许可以从规范中挖掘出来。
好的,所以解决方案(感谢@thehennyy):
using System;
using System.Linq;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
var testTuple = GimeTuples("foo", "bar");
Console.WriteLine(testTuple);
Console.ReadKey();
}
public static object GimeTuples<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
object[] constructorArguments = values.Cast<object>().ToArray();
return Activator.CreateInstance(specificType, constructorArguments);
}
}
}
这会强制编译器将通用数组元素作为参数传递,而不是将整个数组作为单个参数传递。
我对以下代码有一个非常奇怪的问题:
using System;
using System.Linq;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
var testTuples1 = GimeStringTuples("foo", "bar");
var testTuples2 = GimeTuples("foo", "bar");
Console.ReadKey();
}
public static object GimeStringTuples(params string[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(string)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
return Activator.CreateInstance(specificType, values);
}
public static object GimeTuples<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
dynamic result;
string[] testArgs = { "foo", "bar" };
result = Activator.CreateInstance(specificType, testArgs);
result = Activator.CreateInstance(specificType, values);
return result;
}
}
}
它在倒数第二行失败:
result = Activator.CreateInstance(specificType, values);
这很奇怪,因为它与之前执行的行基本相同:
result = Activator.CreateInstance(specificType, testArgs);
在这两种情况下,相同的参数作为 specificType
参数传递,string[2]
作为第二个参数传递。
而且 GimeStringTuples
方法工作得很好......虽然那里没有涉及泛型 - 这可能是提示。
谁能解释这种不寻常的行为?
我可以告诉你发生了什么。查看生成的程序集,您可以看到编译器引入了一个 object[]
包装 values
参数:
Activator.CreateInstance(specificType, new string[] { "foo", "bar" });
Activator.CreateInstance(specificType, new object[] { values });
现在找不到正确的重载了。 如果您添加演员表,您将获得预期的结果并且代码再次运行:
Activator.CreateInstance(specificType, values as string[])
但我不能告诉你为什么会这样,也许可以从规范中挖掘出来。
好的,所以解决方案(感谢@thehennyy):
using System;
using System.Linq;
namespace ConsoleApp1
{
public class Program
{
public static void Main(string[] args)
{
var testTuple = GimeTuples("foo", "bar");
Console.WriteLine(testTuple);
Console.ReadKey();
}
public static object GimeTuples<T>(params T[] values)
{
Type genericType = Type.GetType("System.Tuple`" + values.Length);
Type[] typeArgs = values.Select(_ => typeof(T)).ToArray();
Type specificType = genericType.MakeGenericType(typeArgs);
object[] constructorArguments = values.Cast<object>().ToArray();
return Activator.CreateInstance(specificType, constructorArguments);
}
}
}
这会强制编译器将通用数组元素作为参数传递,而不是将整个数组作为单个参数传递。