我有可以包含其他结构的结构和一个具有两个属性的类,一个用于字段名称,另一个用于字段值。
示例结构:
public struct MyStruct
{
public string Name;
public ushort Code;
public Details Info;
}
public struct Details
{
public string Architecture;
public string Characteristics;
public uint Size;
}
我的课程:
public class Item
{
public string Name { get; set; }
public object Value { get; set; }
public Item(string name, object value)
{
Name = name;
Value = value;
}
}
现在我需要一个函数,其中输入参数是一个结构(可以包含其他结构)并返回一个List的Item。 对于没有其他结构的结构,我有一个完全有效的函数:
private static List<Item> structToList<T>(T structure)
{
List<Item> items = new List<Item>();
foreach (var field in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
items.Add(new Item(field.Name, field.GetValue(structure)));
return items;
}
我很确定这可以递归解决。我的第一个想法是检查字段是结构还是值。如果它是一个结构,请再次调用该函数,如果它是一个值,则将其添加到列表中。此外,我必须在函数之外声明我的List的实例,避难所不是吗?这是我提出的伪代码,所以我无法检查FieldInfo是否是一个结构,并为函数提供了正确的Generic。
List<Item> items = new List<Item>();
private static List<Item> structToList<T>(T structure, List<Item> items)
{
foreach (var field in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
//if(isStructure(field)
// structToList<?>(field, items);
//else
items.Add(new Item(field.Name, field.GetValue(structure)));
}
return items;
}
修改
案件的区别现在有效。对于else子句,我使用this answer,其中类型在执行时已知,但我得到空引用异常。另外field.GetType()并没有给我结构的类型。
private List<Item> structToList<T>(T structure, uint offset)
{
foreach (var field in typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (IsSimple(field.FieldType))
itemList.Add(new Item(field.Name, field.GetValue(structure)));
else
{
// doesn't work
Type t = field.GetType();
MethodInfo method = GetType().GetMethod("structToList")
.MakeGenericMethod(new Type[] { t }); // null reference exception
method.Invoke(this, new object[] { field, 0 });
}
}
return itemList;
}
private static bool IsSimple(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
编辑2: 我想出了符合我需要的two solutions。
答案 0 :(得分:0)
您需要解决的问题(如您所述):
首先,您需要检测字段类型何时为struct
或&#34;简单&#34;值。为此,我建议您阅读this问题的答案。
现在,为了递归地执行此操作,我将删除泛型参数,并在传递给方法的任何typof()
上执行struct
。这将使调用内部struct
的方法变得更加容易,因为您不需要做一些反思&#34;繁重的提升&#34;只是设置具有特定类型的structToList
泛型方法。
答案 1 :(得分:0)
我提出了两个适当的解决方案,我应该解决我的问题。 两种方式都避免使用泛型,因为我们假设在编译时我们不知道结构中结构的类型。
1)首先,我使用了in this answer这个函数来区分它是primitive数据类型,它是由某些特殊情况扩展的,例如字符串,基本上是一个字符数组。在能够确定下一个字段是否为结构之后,您可以再次递归调用函数或将其添加到列表中。
private List<Item> _itemList = new List<Item>();
private List<Item> structToList(object structure)
{
foreach (var field in structure.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (!IsSimple(field.FieldType))
structToList(field.GetValue(structure));
else
_itemList.Add(new Item(field.Name, field.GetValue(structure)));
}
return _itemList;
}
private static bool IsSimple(Type type)
{
return type.IsPrimitive
|| type.IsEnum
|| type.Equals(typeof(string))
|| type.Equals(typeof(decimal));
}
2)第二个解决方案使用Type.IsNested属性来实现相同的目标。
private List<Item> _itemList = new List<Item>();
private List<Item> structToList1(object structure)
{
foreach (var field in structure.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
if (field.FieldType.IsNested)
structToList(field.GetValue(structure));
else
_itemList.Add(new Item(field.Name, field.GetValue(structure)));
}
return _itemList;
}