【问题标题】:Value types of variable size可变大小的值类型
【发布时间】:2011-06-03 18:34:51
【问题描述】:

我正在尝试用 C# 编写一个小型数学库。我想创建一个通用向量结构,用户可以在其中定义元素类型(int、long、float、double 等)和维度。

我的第一次尝试是这样的......

public struct Vector<T>
{
    public readonly int Dimensions;
    public readonly T[] Elements;

    // etc...
}

不幸的是,Elements 作为一个数组,也是一个引用类型。因此,这样做,

Vector<int> a = ...;
Vector<int> b = a;
a[0] = 1;
b[0] = 2;

将导致 a[0]b[0] 都等于 2。

我的第二次尝试是定义一个接口IVector&lt;T&gt;,然后使用Reflection.Emit在运行时自动生成合适的类型。生成的类大致如下所示:

public struct Int32Vector3 : IVector<T>
{
    public int Element0;
    public int Element1;
    public int Element2;

    public int Dimensions { get { return 3; } }

    // etc...
}

这似乎很好,直到我发现接口似乎像对底层对象的引用一样。如果我将IVector 传递给函数,函数中元素的更改将反映在原始向量中。

我认为我的问题是我需要能够创建具有用户指定数量的字段的类。我不能使用数组,也不能使用继承。

有人有解决办法吗?

编辑:这个库将在性能关键的情况下使用,所以引用类型不是一个选项。

【问题讨论】:

  • 你可以简单地创建一个复制构造函数,人们必须知道 Vector 是一个引用类型,所以一个简单的赋值可能不是他们想要的。
  • 有什么问题?我根本不明白你想要做什么。你想解决什么问题?您似乎误解了引用的分配是什么。在您的示例中,对于 a 和 b,在 b=a 之后,b 和 a 指的是同一个 Vector 实例。
  • b 和 a 不引用同一个实例 - Vector 是一个值类型。但是,它们的两个Elements 字段都引用了同一个实例,这是第一次尝试的问题。
  • 糟糕。错过了它是一个结构。

标签: c# .net math


【解决方案1】:

你的类中需要一个Clone 函数MemberwiseClone

类似于以下内容:

class Vector : ICloneable {
    //...
    public Vector Clone() { return (Vector)this.MemberwiseClone(); }
    object ICloneable.Clone() { return Clone(); }
}

【讨论】:

  • -1 这也不起作用。您需要执行深度克隆。 (这种方法仍然不会复制数组,它只是复制引用。无论如何,MemberwiseClone 对于值类型来说是完全没有必要的。)
  • 我隐约记得在 Effective C# 中读过一些关于 ICloneable 是邪恶的内容。我去查一下。
  • @YellPika: ICloneable 不是邪恶的。
  • @YellPika,只是不推荐。看到这个问题:stackoverflow.com/questions/699210/…
  • @Danny 在此评论中由于通知系统。
【解决方案2】:

使用这样的东西:

public struct Vector<T>
{
    public readonly int Dimensions;
    public readonly T[] Elements;

    public Vector(Vector<T> source)
    {
        Dimensions = source.Dimensions;

        Elements = source.Elements != null ?
            (T[])source.Elements.Clone()
            : null;
    }

    public Vector<T> Clone()
    {
        return new Vector<T>(this);
    }

    // etc...
}

然后,当您要传递结构的副本时,您必须确保使用复制构造函数或 Clone 方法。

【讨论】:

  • 这意味着每次我想将向量传递给函数时,我都必须执行 someVar.Clone() ,这在这种情况下很常见。这是很多个新数组。
  • @Yell:好吧,你不能一边吃蛋糕一边吃。如果要复制数组,请复制它。如果你不这样做,不要。
【解决方案3】:

再一次,我在淋浴时顿悟了。

我想我正在寻找类似var x = new Vector&lt;int, 4&gt;(); 的东西,这在 C# 中是不可能的。所以,记住this,我目前的解决方案是:

public struct Vector<TElement, TImpl> where TImpl : struct, IImplementation<TElement>
{
    private TImpl impl;

    public int Dimensions { get { return impl.Dimensions; } }

    public TElement this[int index]
    {
        get { return impl[index]; }
        set { impl[index] = value; }
    }
}

感谢所有回复的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-07
    • 2012-07-19
    • 2013-12-19
    • 2012-11-14
    • 2021-02-26
    • 1970-01-01
    相关资源
    最近更新 更多