在构造函数参数中激活具有通用数组的通用类型的问题

3

我对以下代码有一个非常奇怪的问题:

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方法可以正常工作...尽管那里没有涉及泛型,这可能是提示。
有人能解释一下这种不寻常的行为吗?
2个回答

1
我可以告诉你发生了什么。查看生成的汇编代码,您会发现编译器引入了一个包装values参数的object[]
Activator.CreateInstance(specificType, new string[] { "foo", "bar" });
Activator.CreateInstance(specificType, new object[] { values });

现在无法找到正确的过载。如果添加一个转换,您将获得预期的结果,并且代码再次正常工作:
Activator.CreateInstance(specificType, values as string[])

但我无法告诉你为什么会发生这种情况,也许可以从规格中挖掘出来。

感谢@thehennyy...这给了我足够的线索。可以通过在第一次将值数组转换为object[]来避免这种情况。这似乎是编译器处理泛型数组时的微妙之处,当将它们作为参数传递给具有params签名的方法时...它将整个数组作为单个参数传递而不是传递数组的每个元素。奇怪! - James Crosswell

0

好的,解决方案如下(感谢@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);
        }
    }
}

这会强制编译器将通用数组元素作为参数传递,而不是将整个数组作为单个参数传递。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接