我从输入中得到一组名为weight0
,weight1
... weight49
的双变量。
我想动态地将它们插入到double
数组中以便于操作。
但不是像每个人一样调用:Weights[0] = weight0
... Weights[49] = weight49
我想用一个循环来做。
有办法吗?
答案 0 :(得分:4)
不,基本上 - 除非你的意思是你创建数组的同时:
var weights = new[] {weight0, weight1, weight2, ... , weight48, weight49};
就个人而言,我很想摆脱 50个变量,并从一开始就使用数组,但在所有情况下都可能无法实现。
答案 1 :(得分:1)
你可以使用反射来从变量名中确定数组的索引,但这远非有效。有关详细信息,请参阅此post。
答案 2 :(得分:0)
我会尝试使用KeyValuePair- Listobject
// sample data
var weight = 1.00;
// create a list
var tmp = new List<KeyValuePair<string,object>>();
// Here you can add your variables
tmp.Add(new KeyValuePair<string,object>("weights" + tmp.Count.ToString()
, weight));
// If needed convert to array
var weights = tmp.ToArray();
// get the information out of the array
var weightValue = weights[0].Value;
var weightKey = weights[0].Key;
我认为这将为您提供阵列所需的所有选项。试一试。
答案 3 :(得分:0)
我这样做是因为你可以这样做 - 只要这些变量实际上是字段/属性。你应该是否是另一回事 - 这个解决方案虽然可重用,但速度很慢(需要代理缓存)而且我不得不说我同意Marc Gravell - 如果可以的话,考虑使用整个数组。
如果变量是属性,则需要更改。此外,如果你需要一次性将数组写回变量(因为这个解决方案生成一个包含所有双精度副本的数组,我不会考虑创建一个带有盒装双精度的对象数组),这需要另一种方法......
所以这里。首先是代码/扩展方法的圣墙:
//paste this as a direct child of a namespace (not a nested class)
public static class SO8877853Extensions
{
public static TArray[] FieldsToArray<TObj, TArray>(this TObj o,string fieldPrefix)
{
if(string.IsNullOrWhiteSpace(fieldPrefix))
throw new ArgumentException("fieldPrefix must not null/empty/whitespace",
"fieldPrefix");
//I've done this slightly more expanded than it really needs to be...
var fields = typeof(TObj).GetFields(System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic)
.Where(f =>f.Name.StartsWith(fieldPrefix) && f.FieldType.Equals(typeof(TArray)))
.Select(f =>new{ Field = f, OrdinalStr = f.Name.Substring(fieldPrefix.Length)})
.Where(f => { int unused; return int.TryParse(f.OrdinalStr, out unused);})
.Select(f => new { Field = f.Field, Ordinal = int.Parse(f.OrdinalStr) })
.OrderBy(f => f.Ordinal).ToArray();
//doesn't handle ordinal gaps e.g. 0,1,2,7
if(fields.Length == 0)
throw new ArgumentException(
string.Format("No fields found with the prefix {0}",
fieldPrefix),
"fieldPrefix");
//could instead bake the 'o' reference as a constant - but if
//you are caching the delegate, it makes it non-reusable.
ParameterExpression pThis = Expression.Parameter(o.GetType());
//generates a dynamic new double[] { var0, var1 ... } expression
var lambda = Expression.Lambda<Func<TObj, TArray[]>>(
Expression.NewArrayInit(typeof(TArray),
fields.Select(f => Expression.Field(pThis, f.Field))), pThis);
//you could cache this delegate here by typeof(TObj),
//fieldPrefix and typeof(TArray) in a Dictionary/ConcurrentDictionary
return lambda.Compile()(o);
}
}
上面的扩展方法适用于任何类型。它在实例类型和所需的数组类型上都是通用的,以简化代码中lambda的创建 - 但 并不是通用的。
您传入一组字段的名称前缀 - 在您的情况下为"weight"
- 然后它会搜索所有公共和私有实例字段,以查找具有该前缀且具有后缀的那些字段,该后缀可以解析为整数。然后它根据该序数对这些字段进行排序。它不检查序数列表中的间隙 - 因此weight0
和weight2
的类型可以工作,但只能创建一个双元素数组。
然后它使用表达式树烘焙一段动态代码,编译它(此时,如代码中所述,最好将委托缓存到TObj
和TArray
以备将来使用使用)然后执行它,返回结果。
现在将其添加到标准单元测试项目中的测试类中:
private class SO8877853
{
private double field0 = 1.0;
private double field1 = -5.0;
private double field2 = 10.0;
public double[] AsArray()
{
//it would be nice not to have to pass both type names here - that
//can be achieved by making the extension method pass out the array
//via an 'out TArray[]' instead.
return this.FieldsToArray<SO8877853, double>("field");
}
}
[TestMethod]
public void TestThatItWorks()
{
var asArray = new SO8877853().AsArray();
Assert.IsTrue(new[] { 1.0, -5.0, 10.0 }.SequenceEqual(asArray));
}
就像我说的那样 - 我不是在纵容这样做,我也不期待任何+ 1s - 但我是一个挑战的傻瓜:)