【问题标题】:How could I set a value to a fieldInfo with jagged array type through reflection?如何通过反射将值设置为具有锯齿状数组类型的 fieldInfo?
【发布时间】:2014-10-24 07:14:03
【问题描述】:

我有一个 TileType[][] 类型的 fieldInfo。如何为这个 fieldInfo 设置值?

internal static class Program
{
    private struct Data
    {
        public enum TileType : byte
        {
            Passable,
            Unpassable
        }
        public TileType[][] TileTypes;
    }
    private static T LoadData<T>(string[] values)
    {
        var t = (T)Activator.CreateInstance(typeof(T));
        object boxed = t;
        FieldInfo field = boxed.GetType().GetField("TileTypes"); // I get TileType[][] field here.

        IList<IList<string>> tilesMatrix = new string[values.Length][];

        for (byte x = 0; x < values.Length; x++)
        {
            tilesMatrix[x] = new string[values.Length];
            tilesMatrix[x] = values;
        }

        SetValuesToJaggedArray<object, byte[], byte>(boxed, field, tilesMatrix);
        return (T)boxed;
    }
    private static void SetValuesToJaggedArray<T, TTarget, TTargetElement>(T obj, FieldInfo field, IList<IList<string>> values)
    {
        var objs = new Array[values.Count];

        for (ushort x = 0; x < values.Count; x++)
        {
            var ar = new TTarget[values.Count];

            var arobjs = new object[values.Count];

            for (ushort y = 0; y < values.Count; y++)
            {
                var elements = new List<TTargetElement>();
                for (ushort z = 0; z < values[y].Count; z++)
                {
                    var element = (TTargetElement)Convert.ChangeType(values[y][z], typeof(TTargetElement), CultureInfo.InvariantCulture);
                    elements.Add(element);
                }
                object bElts = elements.ToArray();
                var value = (TTarget)bElts;
                arobjs[y] = value;
            }

            Array.Copy(arobjs, ar, values.Count);
            objs[x] = new TTarget[values.Count];
            Array.Copy(ar, objs[x], values.Count);
        }
        object b = objs;
        field.SetValue(obj, b); // Exception here!
    }
    static void Main(string[] args)
    {
        Data d = LoadData<Data>(new string[4] { "0", "1", "2", "3" });
    }
}

我从行 field.SetValue(obj, b); 得到异常因为我不知道如何在那里设置一个值。任何帮助表示赞赏。

已解决,感谢米奇解答:

internal static class Program
{
    public struct Data
    {
        public enum TileType : byte
        {
            Passable,
            Unpassable,
            Water,
            Empty
        }
        public TileType[][] TileTypes;
    }
    private static T LoadData<T>(string[][] values)
    {
        var t = (T)Activator.CreateInstance(typeof(T));
        object boxed = t;
        FieldInfo field = boxed.GetType().GetField("TileTypes"); // I get TileType[][] field here.
        SetValuesToJaggedArray<object, byte>(boxed, field, values);
        return (T)boxed;
    }
    private static void SetValuesToJaggedArray<T, TTargetElement>(T obj, FieldInfo field, string[][] values)
    {
        var objs = new TTargetElement[values.Length][];
        for (ushort x = 0; x < values.Length; x++)
        {
            var elements = new TTargetElement[values.Length];
            for (ushort y = 0; y < values.Length; y++)
            {
                var element = (TTargetElement)Convert.ChangeType(values[x][y], typeof(TTargetElement), CultureInfo.InvariantCulture); 
                elements[y] = element;
            }
            objs[x] = elements;
        }
        field.SetValue(obj, objs);
    }
    static void Main()
    {
        var matrix = new string[4][];
        matrix[0] = new[] { "0", "1", "2", "3" };
        matrix[1] = new[] { "1", "2", "3", "0" };
        matrix[2] = new[] { "2", "3", "0", "1" };
        matrix[3] = new[] { "3", "0", "1", "2" };
        var d = LoadData<Data>(matrix);
        const string whiteSpace = " ";
        for (byte x = 0; x < d.TileTypes.Length; x++)
        {
            for (byte y = 0; y < d.TileTypes.Length; y++)
                Console.Write(d.TileTypes[x][y] + whiteSpace);
            Console.WriteLine();
        }
        Console.ReadKey();
    }
}

【问题讨论】:

  • 有什么异常?它在信息中说了什么?为什么要使用反射和泛型?为什么Data 定义为struct?
  • @JeanHominal 例外是:无法将 Array[] 转换为 TileType[][]。我使用反射和泛型因为我反序列化来自文本文件的数据。 “数据”被定义为“结构”,因为我实际上不需要引用类型作为我将进一步使用的输出类型。我只会从该结构中获取数据一次,然后将其从内存中删除。
  • 你不需要需要反射和泛型来反序列化。您对 struct 的使用没有充分的理由,在 C# 中,struct 仅在证明有好处时才使用。使用ushort 和byte 作为数组索引是非惯用且徒劳的,因为这些值将由[] 运算符转换为int。您在矩阵的每一行中都影响了相同的 values 对象 - 您是否希望 tilesMatrix[y] = values 复制该对象?一旦将值 "2" 和 "3" 转换为 TileType,您期望得到什么结果?我感觉你平时写的是C++。
  • 另外,我不明白为什么当你可以直接返回 TileType[][] 时返回 Data 结构。
  • @JeanHominal '您对结构的使用没有充分的理由,在 C# 中,只有在证明有好处时才会使用结构。'请举例:)。 'tilesMatrix[y] = values' 这些不是矩阵的实际值。因为在我的机器上使用 ushort 比使用 int 更快。

标签: c# .net reflection


【解决方案1】:

如果您跳过示例的其余部分,则剩下以下内容:

struct Data
{
    byte[][] TitleTypes;
}

static void Main(string[] args) 
{
    var d = new Data();
    var field = typeof(Data).GetField("TitleTypes");

    var newValue = new byte[5];
    // This line fails because you are setting a field of type byte[][] with 
    // a value of byte[]
    field.SetValue(d, newValue);
}

要么在数组中设置一个特定的索引,要么将TitleTypes 设置为具有适当锯齿状数组的值。有关原因和方式的详细信息,请参阅Setting value in an array via reflection。

static void Main(string[] args) 
{
    var d = new Data();
    var field = typeof(Data).GetField("TitleTypes");

    // set to index 0
    var newValue = new byte[5];
    var arrTarget = (byte[][])field.GetValue(d);
    arrTarget[0] = newValue;

    // replace entire array
    var newArray = new byte[5][];
    field.SetValue(d, newArray);
}

【讨论】:

  • 谢谢,您的回答帮助我解决了问题。
猜你喜欢
  • 2023-03-03
  • 2012-06-04
  • 1970-01-01
  • 2012-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-15
  • 2017-09-21
相关资源
最近更新 更多