在foreach循环中访问List<object[]>数组元素

5

这是我拥有的内容:

List<object[]> markers = new List<object[]>();

object[] marker = new object[2];
marker[0] = new Vector2(1, 2);
marker[1] = new Vector4(1, 2, 3, 4);
markers.Add(marker);

foreach (var item in markers)
{
    int x = (Vector2)item[0].X; // Error: 'object' does not contain a definition
                                // for 'X' and no extension method 'X' accepting
                                // a first argument of type 'object' could be
                                // found (are you missing a using directive or
                                // an assembly reference?)
    // other stuff
}

有没有一种方法可以在不丧失代码可读性的情况下使其工作,或者我应该尝试使用类而不是对象数组?

1
一个类比一个对象数组更好。 - Ben Voigt
3
没问题!使用类可以更清晰、易读地表达。 - Mare Infinitus
4
然后您将会收到一个 InvalidCastException(无效转换异常),因为您无法将一个 Vector4 强制转换为一个 Vector2 (至少我在 MSDN 上没有找到它们之间的共同祖先)。 - Ed S.
“marker”对象的作用是什么?我可能错了,但似乎您多了一层无用的对象,反而让事情更加混乱。 - naspinski
@naspinski 我正在制作一个调试方法,当满足特定条件时,在特定坐标处绘制用户定义颜色的标记。 - user1306322
7个回答

4

您需要执行此操作(运算符优先级问题)

((Vector2)item[0]).X;

然而,我认为在同一个数组中使用不同的对象类型并不是一个好的做法。这就是为什么引入了泛型列表(ArrayList 缺乏类型安全性)的原因。
您的代码试图执行以下操作:
ArrayList vectors = new ArrayList { new Vector2(22, 33), new Vector4(223, 43, 444, 33}};

这是在 .Net 2.0 之前发生的事情,它引起了一些问题。

1
奇怪的是,当我第一次尝试时,它也没有起作用,但重新加载项目后就可以了。在之前,重新加载项目曾经多次帮助我解决问题 :p - user1306322

1

我会编写类,而不是使用内置的结构体Vector2Vector4,并让它们实现一个公共接口。这使您能够在声明数据结构时使用特定类型,而不是使用类型object

尝试像这样:

public class MyVector2 : IVector {

    //...
}

public class MyVector4 : IVector {

    //...
}

public interface IVector {


}

然后按照以下方式声明您的结构:

List<IVector> list = new List<IVector>();
IVector[] arr = new IVector[someSize];

如果类型Vector2Vector4是一些自定义类型,而不是来自System.Windows.Vector2System.Windows.Vector4,您可以对它们进行子类化,并按照上述描述的方式进行操作:

public class MyVector2 : Vector2, IVector {

}

public class MyVector4 : Vector4, IVector {

}

只是一个提议。


Vector2 是一个结构体,因此不能被扩展。http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.vector2.aspx - Tim S.
我原以为Vector2是用户创建的一个类,没想到它与XNA框架有关。 - DarthVader

1
如果您正在使用.NET 4且不想创建新的类,Tuple是您可以使用的内容:
List<Tuple<Vector2, Vector4>> markers = new List<Tuple<Vector2, Vector4>>();

1

你现在做的很糟糕。为什么不用接口编程,然后通过迭代列表来完成操作呢?这样就不需要强制类型转换,而且可以根据你的合同进行其他操作。在这种情况下,你并不真正知道哪个对象是vector2或vector4。当然你可以找出来,但那会非常丑陋。

这样做会更加灵活、可扩展和易于维护。虽然我不太清楚你在做什么,但我会选择这种方式。

我会按照以下步骤进行:

interface IVector<T>
{
   List<T> Someobjectcollections
   void YourCommonOperation()

}

class Vector2 : IVector<Vector2>
{
 // override

}

class Vector4 : IVector<Vector4>
{
   // override
}

List<IVector> markers = new List<IVector>();

...


foreach (var item in markers)
{ 
     items.commonoperation();

      ....
}

你正在做的是复制答案 开玩笑 ;) - marc wellman
1
笑。我只是在给你评论而已。你就像史蒂夫·乔布斯一样,兄弟。你抄袭了我的东西。 - DarthVader

1
你应该绝对重构代码来使用类。基本上,你需要一个标记列表,每个标记可以容纳一个或多个向量,每个向量又包含一个或多个数字。这是一种简单的方法来实现它,而不使用继承:
public class Marker
{
    public List<Vector> { get; set; }
}

public class Vector
{
    public int[] Numbers { get; private set; }

    public Vector(params int[] numbers)
    {
        Numbers = numbers;
    }
}

然后,您可以简单地使用List<Marker>


1
我决定选择Tuple。感谢那位后来删除回答的发帖者提供的建议。你的英勇事迹将被铭记。
编辑:不得不将Vector4更改为Color(alpha通道始终为255)。
结果:
// declaration
List<Tuple<Vector2, Color>> markers = new List<Tuple<Vector2, Color>>();

// adding items
Tuple<Vector2, Color> marker = new Tuple<Vector2, Color>(
    new Vector2(x, y), Color.FromNonPremultiplied(250, 200, 150, 100));       
markers.Add(marker);

// retrieving item values
foreach (var item in markers)
{
    int x = item.Item1.X;
    int y = item.Item1.Y;
    Color mycolor = item.Item2;
}

它能工作,但我还没有测试过CPU效率,如果它比其他提出的解决方案慢的话,我会考虑使用其他解决方案。


0

这里可能是一个很好的起点:

public class Markers
{
    public Vector2 V2 { get; set; }
    public Vector4 V4 { get; set; }

    public Markers() {}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接