【问题标题】:Direct dynamic conversion to array of different type直接动态转换为不同类型的数组
【发布时间】:2019-12-02 18:28:22
【问题描述】:

我一定遗漏了一些明显的东西,但我没有找到将Object[] 类型的数组转换为TE[] 类型的数组的直接方法,而TE 仅在运行时知道。

这是我正在努力实现的工作版本:

using System;
using System.Globalization;
using System.Linq;

namespace TestArrays
{
    class Program
    {
        static T Parse<T>(string s)
        {
            T result;

            if (typeof(T).IsArray)
            {
                var TE = typeof(T).GetElementType();
                var rawResult = s.Split(',').Select(x => Convert.ChangeType(x, TE, CultureInfo.InvariantCulture)).ToArray();
                result = (T)(object)Array.CreateInstance(TE, rawResult.Length);
                Array.Copy(rawResult, (Array)(object)result, rawResult.Length);
            }
            else
            {
                result = (T)Convert.ChangeType(s, typeof(T), CultureInfo.InvariantCulture);
            }

            return result;
        }

        static void Main(string[] args)
        {
            Console.WriteLine(Parse<object>("abc"));
            Console.WriteLine(Parse<string>("abc"));
            Console.WriteLine(Parse<int>("123456"));
            Console.WriteLine(Parse<double>("123.456"));

            Console.WriteLine(Parse<object[]>("a,b,c"));
            Console.WriteLine(Parse<string[]>("a,b,c"));
            Console.WriteLine(Parse<int[]>("123,456,789"));
            Console.WriteLine(Parse<double[]>("123.456,456.789,789.101112"));
        }
    }
}

我想将 Object[] 类型的 rawResult 转换为预期的返回类型 TE[]

我知道直接转换并不总是可行的,因为数组元素的大小可能会有所不同。
但在这里我想转换为另一种引用类型,这样就可以就地完成,而不必创建新数组并分配相同数量的内存。

此外,可以保留元素,因为它们已经是目标 TE 类型的引用。

我见过Array.ConvertAll,但它也会返回Object[]

【问题讨论】:

  • 这是一个奇怪的要求。你有没有仔细考虑过这是否真的是你想要做的?我会考虑使用像 JSON 这样的标准序列化/反序列化格式,并利用框架来处理转换。
  • 具体用例是 .NET Core 配置 API,它返回一些 object[] 我想转换为特定的 T[]。无论如何,现在我想知道。 :)
  • 所以配置 API 返回一个 object[] 并且您碰巧知道,在您的特定情况下,该数组中应该只有 ints 吗?这是一个非常不同的问题,而且更容易解决。使用 LINQ var intArray = objectArray.Cast&lt;int&gt;().ToArray();
  • 调用者知道,它调用的不是我自己的通用函数T Get&lt;T&gt;(string configParamPath)。 :)
  • 调用者可以相对轻松地调用Get&lt;object[]&gt;().Cast&lt;int&gt;()。这很简单,不需要反思。或者,您可以创建一个 GetArray&lt;T&gt;() 辅助方法,该方法在内部传递到 Get&lt;object[]&gt;().Cast&lt;T&gt;().ToArray()。由于框架已经创建了一个 object[],因此您无法避免分配另一个数组,除非您愿意返回类似 IEnumerable&lt;&gt; 的内容。

标签: c# arrays .net


【解决方案1】:

至少我们可以为数组创建一个新方法:

static T[] ParseArray<T>(string s)
{
    var result = s.Split(',').Select(x => (T)Convert.ChangeType(x, typeof(T), CultureInfo.InvariantCulture)).ToArray();
    return result;
}

并从Parse&lt;t&gt;()调用这个方法:

static T Parse<T>(string s)
{
    T result;
    if (typeof(T).IsArray)
    {
        var TE = typeof(T).GetElementType();

        MethodInfo method = typeof(Program).GetMethod("ParseArray", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
        MethodInfo generic = method.MakeGenericMethod(TE);
        result = (T)generic.Invoke(null, new object[] { s });
    }
    else
    {
        result = (T)Convert.ChangeType(s, typeof(T), CultureInfo.InvariantCulture);
    }

    return result;
}

【讨论】:

  • 如果你使用反射,你可以直接使用TE作为通用参数调用ParseArray,而不是使用硬编码的switch case。
  • @StriplingWarrior 好收获!
  • @BasilKosovan 感谢这个想法。 +1 :)
  • 您需要更好的主意吗?
  • @BasilKosovan 只是稍等一下以防万一。 :)
猜你喜欢
  • 1970-01-01
  • 2016-09-19
  • 1970-01-01
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 2016-09-17
相关资源
最近更新 更多