[英]Getting the value of a tuple using reflection
so I'm trying to get a tuple's value using reflection, the only problem is that I get an exception: System.Reflection.TargetInvocationException.所以我试图使用反射来获取元组的值,唯一的问题是我得到了一个异常:System.Reflection.TargetInvocationException。 I've tried getting its value as one comment suggested here: Casting to a Tuple<object,object> , var itemX = t.GetProperty("ItemX").GetValue(data);
我已经尝试按照此处建议的一条评论获取其值: Casting to a Tuple<object,object> , var itemX = t.GetProperty("ItemX").GetValue(data);
If I uses lem.FieldType.GetProperty("Item1").Name , I can get the name back as Item1, Item2 , etc..., am I using it correctly or is there any other way?如果我使用 lem.FieldType.GetProperty("Item1").Name ,我可以将名称恢复为 Item1, Item2 等...,我是否正确使用它还是有其他方法?
FieldInfo[] fields = this.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
FieldInfo[] tuples = fields.Where(field=>typeof(IStructuralEquatable).IsAssignableFrom(field.FieldType) && typeof(IStructuralComparable).IsAssignableFrom(field.FieldType)).ToArray();
Debug.WriteLine(tuples.Length.ToString()" ->");
foreach (var elem in tuples)
{
Debug.WriteLine(elem.FieldType.GetProperty("Item1").GetValue(this,null).ToString());
PropertyInfo[] info = elem.FieldType.GetProperties();
Debug.WriteLine(info[0].GetValue(this,null).ToString());
for(int i=0;i<info.Length;i++)
{
Debug.WriteLine(info[i].GetValue(this,null).ToString());
}
And my tuple:还有我的元组:
protected Tuple<string,int, int, int> testTuple = new Tuple<string, int, int, int>("Test",1,0,1);
Let's query tuple
for its Item1..ItemN
properties;让我们查询tuple
的Item1..ItemN
属性; we can do it with a help of Linq and regular expressions , eg我们可以借助Linq和正则表达式来完成,例如
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
...
Dictionary<string, object> result = testTuple
.GetType()
.GetProperties()
.Where(prop => prop.CanRead)
.Where(prop => !prop.GetIndexParameters().Any())
.Where(prop => Regex.IsMatch(prop.Name, "^Item[0-9]+$"))
.ToDictionary(prop => prop.Name, prop => prop.GetValue(testTuple));
Time to wrap it into your method:是时候将它包装到您的方法中了:
...
foreach (var tuple in tuples) {
var result = tuple
.GetType()
.GetProperties()
.Where(prop => prop.CanRead)
.Where(prop => !prop.GetIndexParameters().Any())
.Where(prop => Regex.IsMatch(prop.Name, "^Item[0-9]+$"))
.Select(prop => new {
name = prop.Name,
value = prop.GetValue(tuple),
});
foreach (var item in result)
Debug.WriteLine($"{item.name} = {item.value}");
}
...
Edit: let's start from getting all fields which are of type Tuple<,...,>
(see comments below):编辑:让我们从获取Tuple<,...,>
类型的所有字段开始(请参阅下面的评论):
Object objectToInspect = this;
HashSet<Type> typleTypes = new HashSet<Type>() {
typeof(Tuple<>),
typeof(Tuple<,>),
typeof(Tuple<,,>),
typeof(Tuple<,,,>),
typeof(Tuple<,,,,>),
typeof(Tuple<,,,,,>),
typeof(Tuple<,,,,,,>),
typeof(Tuple<,,,,,,,>),
};
var fieldsWithTuples = objectToInspect
.GetType()
.GetFields(BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.FlattenHierarchy)
.Where(field => field.FieldType.IsGenericType)
.Where(field => typleTypes.Contains(field.FieldType.GetGenericTypeDefinition()))
.Select(field => new {
name = field.Name,
value = field.GetValue(field.IsStatic
? null // we should provide null for static
: objectToInspect)
})
.Where(item => item.value != null);
// .Select(item => item.value) // if you want tuple values
// .ToArray(); // materialized as an array
And now we are ready to use my code above:现在我们准备好使用我上面的代码:
foreach (var tuple in fieldsWithTuples.Select(f => f.value)) {
var result = tuple
.GetType()
.GetProperties()
.Where(prop => prop.CanRead)
.Where(prop => !prop.GetIndexParameters().Any())
.Where(prop => Regex.IsMatch(prop.Name, "^Item[0-9]+$"))
.Select(prop => new {
name = prop.Name,
value = prop.GetValue(tuple),
});
foreach (var item in result)
Debug.WriteLine($"{item.name} = {item.value}");
}
Tuple is defined like this: Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>
.元组的定义如下: Tuple<T1,T2,T3,T4,T5,T6,T7,TRest>
。
Following the number of values inside tuple its not the same logic so to read tuple in all case (even with 8 items or more) with reflection just use this piece of code (general coding):遵循元组内的值数量,其逻辑不同,因此要在所有情况下(即使有 8 个项目或更多)通过反射读取元组,只需使用这段代码(通用编码):
public IEnumerable<object> EnumerateValueTuple(object valueTuple)
{
var tuples = new Queue<object>();
tuples.Enqueue(valueTuple);
while (tuples.Count > 0 && tuples.Dequeue() is object tuple)
{
foreach (var field in tuple.GetType().GetFields())
{
if (field.Name == "Rest")
tuples.Enqueue(field.GetValue(tuple));
else
yield return field.GetValue(tuple);
}
}
}
You could use:你可以使用:
var item = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
foreach(var value in EnumerateValueTuple(item))
Console.Out.WriteLine(value); // Prints "1 2 3 4 5 6 7 8 9 10 11"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.