我有一个第三方库返回一个对象数组的对象数组,我可以把它放到一个对象中[]:
object[] arr = myLib.GetData(...);
结果数组由object []条目组成,因此您可以将返回值视为某种记录集,其中外部数组表示行,而内部数组包含字段值,其中某些字段可能未填充(a锯齿状阵列)。要访问各个字段,我必须像:
int i = (int) ((object[])arr[row])[col];//access a field containing an int
现在因为我很懒,我想访问这样的元素:
int i = (int) arr[row][col];
为此,我使用以下Linq查询:
object[] result = myLib.GetData(...);
object[][] arr = result.Select(o => (object[])o ).ToArray();
我尝试使用像object[][] arr = (object[][])result;
之类的简单强制转换,但失败并出现运行时错误。
现在,我的问题:
修改
谢谢大家的快速回答
@James:我喜欢你在新课程中回答罪魁祸首的答案,但缺点是我在接受源数组时总是必须进行Linq包装,而索引器需要行和col值int i = (int) arr[row, col];
(我需要得到一个完整的行,如object[] row = arr[row];
,抱歉没有在开头发布。)
@Sergiu Mindras:像James一样,我认为扩展方法有点危险,因为它适用于所有object[]
个变量。
@Nair:我为我的实现选择了你的答案,因为它不需要使用Linq包装器,我可以使用int i = (int) arr[row][col];
访问两个字段,或使用object[] row = arr[row];
访问整行。
@quetzalcoatl和@Abe Heidebrecht:感谢Cast<>()
的提示。
结论:我希望我能同时选择James和Nair的答案,但正如我上面所说,Nair的解决方案让我(我认为)具有最佳的灵活性和性能。 我添加了一个函数,它将使用上面的Linq语句“展平”内部数组,因为我还有其他需要使用这种结构的函数。
以下是我(大致)实现它的方式(取自Nair的解决方案:
公共类CustomArray { 私有对象[]数据; public CustomArray(object [] arr) { data = arr; }
//get a row of the data
public object[] this[int index]
{ get { return (object[]) data[index]; } }
//get a field from the data
public object this[int row, int col]
{ get { return ((object[])data[row])[col]; } }
//get the array as 'real' 2D - Array
public object[][] Data2D()
{//this could be cached in case it is accessed more than once
return data.Select(o => (object[])o ).ToArray()
}
static void Main()
{
var ca = new CustomArray(new object[] {
new object[] {1,2,3,4,5 },
new object[] {1,2,3,4 },
new object[] {1,2 } });
var row = ca[1]; //gets a full row
int i = (int) ca[2,1]; //gets a field
int j = (int) ca[2][1]; //gets me the same field
object[][] arr = ca.Data2D(); //gets the complete array as 2D-array
}
}
所以 - 再次 - 谢谢大家!使用这个网站总是一种真正的乐趣和启示。
答案 0 :(得分:7)
您可以创建一个包装类来隐藏丑陋的转换,例如
public class DataWrapper
{
private readonly object[][] data;
public DataWrapper(object[] data)
{
this.data = data.Select(o => (object[])o ).ToArray();
}
public object this[int row, int col]
{
get { return this.data[row][col]; }
}
}
<强>用法强>
var data = new DataWrapper(myLib.GetData(...));
int i = (int)data[row, col];
还有机会使包装器具有通用性,例如: DataWrapper<int>
但是,我不确定您的数据集是否都是相同的类型,返回object
使其足够通用,以便您决定需要哪种数据类型。
答案 1 :(得分:3)
几乎没有类似的答案发布,它做了类似的事情。只有当你想要像
这样的时候才会有所不同int i = (int) arr[row][col];
展示这个想法
public class CustomArray
{
private object[] _arr;
public CustomArray(object[] arr)
{
_arr = arr;
}
public object[] this[int index]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal array.
return (object[]) _arr[index];
}
}
static void Main()
{
var c = new CustomArray(new object[] { new object[] {1,2,3,4,5 }, new object[] {1,2,3,4 }, new object[] {1,2 } });
var a =(int) c[1][2]; //here a will be 4 as you asked.
}
}
答案 2 :(得分:1)
(1)这可能可以使用dynamic
关键字以简短的形式完成,但您将使用编译时检查。但考虑到你使用object [],这是一个很小的代价:
dynamic results = obj.GetData();
object something = results[0][1];
我没有用编译器检查它。
(2)而不是Select(o => (type)o)
有一个专用的Cast<>
函数:
var tmp = items.Select(o => (object[])o).ToArray();
var tmp = items.Cast<object[]>().ToArray();
它们几乎相同。我猜Cast会快一点,但是我再没有检查过。
(3)是的,以这种方式改造会在一定程度上影响表现,主要取决于物品的数量。您拥有的元素越多,影响就越大。这主要与.ToArray相关,因为它将枚举所有项目,它将创建一个额外的数组。考虑一下:
var results = ((object[])obj.GetData()).Cast<object[]>();
这里的'结果'是类型IEnumerable<object[]>
,不同之处在于它将被懒惰地枚举,因此对所有元素的额外迭代消失了,临时额外数组消失了,而且开销也很小 - 类似于每个元素的手动转换,无论如何都要做。但是 - 你失去了对最顶层数组进行索引的能力。您可以对其进行循环/ foreach
,但不能将其编入/ [123]
。
编辑:
詹姆斯的包装方式在整体表现方面可能是最好的。我最喜欢它的可读性,但这是个人观点。其他人可能更喜欢LINQ。但我喜欢它。我建议詹姆斯的包装纸。
答案 3 :(得分:1)
您可以使用扩展方法:
static int getValue(this object[] arr, int col, int row)
{
return (int) ((object[])arr[row])[col];
}
通过
检索int requestedValue = arr.getValue(col, row);
不知道arr [int x] [int y]语法。
修改的
感谢詹姆斯的观察
你可以使用一个可以为空的int,这样你就不会在转换时得到异常。
因此,该方法将成为:
static int? getIntValue(this object[] arr, int col, int row)
{
try
{
int? returnVal = ((object[])arr[row])[col] as int;
return returnVal;
}
catch(){ return null; }
}
可以通过
检索int? requestedValue = arr.getIntValue(col, row);
这样你就得到一个可以为空的对象,所有遇到的异常强制返回null
答案 4 :(得分:0)
您可以使用LINQ Cast运算符代替Select ...
object[][] arr = result.Cast<object[]>().ToArray()
这有点不那么冗长,但性能应该几乎相同。另一种方法是手动完成:
object[][] arr = new object[result.Length][];
for (int i = 0; i < arr.Length; ++i)
arr[i] = (object[])result[i];