如何使用 shrink、toArray 和 fromArray 方法改进 System.Tuple
How to improve System.Tuple with shrink, toArray and fromArray methods
我需要在 .Net 中实现一个关于 System.Tuple class 的方法。最好的方法是什么?扩展方法,subclass 整套 Tuple classes 或基于 System.Tuple?
的源代码创建一个新的 class
该方法根据掩码(整数或布尔值)输入 Tuple<T1,T2..Tn>
和 return Tuple<T1..Tm> (m<n)
。如何替换 switch-case 语句和反射的使用?我怎样才能提高性能?
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)
为避免反射,您唯一的选择是为所有元组、元组...通用元组类型创建重载:
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 和 Shrink 的 Return 类型将保持 "object" 无论如何,因为你 return 不同的元组,并且它们不共享任何可用的 public class 或接口。你为什么需要这样做?我觉得您可能不需要使用 Tuple classes 来完成您的任务。
这可能不会提高函数的运行时间,但会避免 switch case。
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>
1) 这与 Amir 的回答相同,只是更像 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) 如果合适,您可以 return 动态决定定义的动态类型。类似于:
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) 最后,您应该能够使用表达式树并使用预编译委托而不是反射来生成 运行-time 元组,但由于这整个事情不是通用的,您将不得不使用DynamicInvoke
这会更慢,所以我不确定性能提升。 DynamicInvoke
s 非常慢,并且是框架中最慢的构造之一。如果性能很重要,您可以编写单独的重载,如 Evk 所示。
我需要在 .Net 中实现一个关于 System.Tuple class 的方法。最好的方法是什么?扩展方法,subclass 整套 Tuple classes 或基于 System.Tuple?
的源代码创建一个新的 class该方法根据掩码(整数或布尔值)输入 Tuple<T1,T2..Tn>
和 return Tuple<T1..Tm> (m<n)
。如何替换 switch-case 语句和反射的使用?我怎样才能提高性能?
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)
为避免反射,您唯一的选择是为所有元组、元组...通用元组类型创建重载:
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 和 Shrink 的 Return 类型将保持 "object" 无论如何,因为你 return 不同的元组,并且它们不共享任何可用的 public class 或接口。你为什么需要这样做?我觉得您可能不需要使用 Tuple classes 来完成您的任务。
这可能不会提高函数的运行时间,但会避免 switch case。
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>
1) 这与 Amir 的回答相同,只是更像 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) 如果合适,您可以 return 动态决定定义的动态类型。类似于:
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) 最后,您应该能够使用表达式树并使用预编译委托而不是反射来生成 运行-time 元组,但由于这整个事情不是通用的,您将不得不使用DynamicInvoke
这会更慢,所以我不确定性能提升。 DynamicInvoke
s 非常慢,并且是框架中最慢的构造之一。如果性能很重要,您可以编写单独的重载,如 Evk 所示。