我需要在System.Tuple中实现一个处理.Net类的方法。做这件事最好的方法是什么?扩展方法,子类完整的元组类,还是创建一个基于System.Tuple源代码的新类?
该方法输入一个Tuple<T1,T2..Tn>,并根据掩码(int或boolean)返回一个Tuple<T1..Tm> (m<n)。如何替换开关-大小写语句和反射的使用?我怎样才能提高性能?
public static object shrink(this object source, params int[] mask)
{
PropertyInfo[] prop = source.GetType().GetRuntimeProperties().ToArray<PropertyInfo>();
object[] tmp = new object[mask.Length];
int index = 0;
for (int i = 0; i < mask.Length; i++)
{
if (mask[i] != 0)
{
tmp[index] = prop[i].GetValue(source, null);
index++;
}
}
switch (index)
{
case 1: return Tuple.Create(tmp[0]);
case 2: return Tuple.Create(tmp[0], tmp[1]);
....
....
}
}以同样的方式,我需要实现一个Tuple到数组,一个数组到Tuple方法。
2) public static object toArray(this object source)输入:Tuple<T1..Tn>输出:object[]
3) public static object FromArray(this object source)输入:object[]输出Tuple<T1..Tn)
发布于 2015-09-20 17:47:38
这很可能不会改善函数的运行时,但它将避免切换情况。
private object StripTuple(object tuple, int[] mask)
{
int[] indexes = mask.Select((v, i) => new { val = v, index = i }).Where(o => o.val == 1).Select(i => i.index).ToArray();
object[] items = new object[indexes.Length];
Type[] tupleTypes = new Type[indexes.Length];
var originalTupleType = tuple.GetType();
var genericArgs = originalTupleType.GetGenericArguments();
for (var i = 0; i < indexes.Length; i++)
{
items[i] = originalTupleType.GetProperty("Item" + (indexes[i] + 1)).GetValue(tuple);
tupleTypes[i] = genericArgs[indexes[i]];
}
Type tupleType = Type.GetType("System.Tuple`" + indexes.Length);
Type newTupleType = tupleType.MakeGenericType(tupleTypes);
return Activator.CreateInstance(newTupleType, items);
}用法:
var t1 = new Tuple<int, int, int, string, double, string, int>(1, 2, 3, "4", 5.7, "6", 7);
var newTuple = StripTuple(t1, new int[7]{0,0,0,1,1,0,1}); // "4",5.7,7函数将获得第一个m参数(m <=元组的长度)。
如果输入为Tuple<int,int,string,int>,长度=3,则输出类型为Tuple<int,int,string>
发布于 2015-09-20 17:18:56
为了避免反射,您唯一的选择是为所有元组创建重载。泛型元组类型:
public static object shrink<T1>(this Tuple<T1> tuple, params int[] mask) {
}
public static object shrink<T1, T2>(this Tuple<T1, T2> tuple, params int[] mask) {
}
...ToArray()方法也是如此。尽管如此,FromArray和收缩的返回类型仍然是"object“,因为您返回不同的元组,并且它们不共享任何可用的公共类或接口。你为什么要这么做?我有种感觉,你可能不需要在你的任务中使用元组类。
发布于 2015-09-20 21:08:14
1)这与埃米尔的回答相同,只是更多的是LINQ。
public static object shrink(this object source, params int[] mask)
{
var props = source.GetType().GetProperties();
var values = mask
.Select((val, index) => new { val, index })
.Where(x => x.val != 0)
.Select(x => props[x.index])
.Select(prop => new { prop, value = prop.GetValue(source) })
.ToList();
var type = Type.GetType("System.Tuple`" + values.Count)
.MakeGenericType(values.Select(x => x.prop.PropertyType).ToArray());
var arguments = values.Select(x => x.value).ToArray();
return Activator.CreateInstance(type, arguments);
}2)如果适合,可以返回动态类型,动态决定定义。类似于:
public static object shrink(this object source, params int[] mask)
{
var props = source.GetType().GetProperties();
var items = mask
.Select((val, index) => new { val, index })
.Where(x => x.val != 0)
.Select((x, index) => new
{
name = "Item" + index,
val = props[x.index].GetValue(source)
})
.ToList();
var expando = new ExpandoObject() as IDictionary<string, object>;
foreach (var item in items)
expando[item.name] = item.val;
return expando;
}3)最后,您应该能够使用表达式树和使用预编译的委托来生成运行时元组,而不是反射,但是由于这整个过程不是泛型的,所以您必须使用DynamicInvoke,这会更慢,所以我不确定性能的提高。DynamicInvoke非常慢,是框架中最慢的构造之一。如果性能很重要,您可以编写单独的重载,如Evk所示。
https://stackoverflow.com/questions/32681711
复制相似问题