C# 在C语言中修改对象#

C# 在C语言中修改对象#,c#,C#,(如果你能想出一个更好的标题,请告诉我。) 我正在做一个路线优化计划。我从路线需要包含的点列表开始。我的第一步是创建一个所有可能路由(排列)的列表。然后,我删除任何我可以删除的路线(例如,如果一站必须在另一站之前)。完成后,我计算每个可能路线中每个点之间的距离和时间。每个点都是一个对象(TPoint),所有距离和时间值都存储在一个名为TData的单独类中,该类存储在TPoint的每个实例中。我的问题是:当我尝试在第一个可能的路线的第一站更新TData时,它将在每个可能的路线中更新相同TP点的TD

(如果你能想出一个更好的标题,请告诉我。)

我正在做一个路线优化计划。我从路线需要包含的点列表开始。我的第一步是创建一个所有可能路由(排列)的列表。然后,我删除任何我可以删除的路线(例如,如果一站必须在另一站之前)。完成后,我计算每个可能路线中每个点之间的距离和时间。每个点都是一个对象(TPoint),所有距离和时间值都存储在一个名为TData的单独类中,该类存储在TPoint的每个实例中。我的问题是:当我尝试在第一个可能的路线的第一站更新TData时,它将在每个可能的路线中更新相同TP点的TData。这是因为类是引用类型,并且存储在堆上。我正在寻找一种解决方案,允许我在每个TPoint上存储TData

下面是一些示例代码(以下代码演示了当我修改一个对象(TPoint)时,我实际上只是使用引用来修改堆上的对象):

Main

// Let's create a list of points we need to hit.
List<TPoint> lstInitial = new List<TPoint>();
lstInitial.Add(new TPoint("A", new TData(-1, -1)));
lstInitial.Add(new TPoint("B", new TData(-1, -1)));
lstInitial.Add(new TPoint("C", new TData(-1, -1)));

// Now let's get all possible routes
IList<IList<TPoint>> lstPermutations = Permutations(lstInitial);

// Let's write these values to the first point, in the first possible route.
lstPermutations[0][0].oTData.distance = 10;
lstPermutations[0][0].oTData.minutes = 20;

foreach (IList<TPoint> perm in lstPermutations)
{
    foreach (TPoint p in perm)
    {
        Response.Write(p.id + "|" + p.oTData.distance + "|" + p.oTData.minutes);
        Response.Write(" ");
    }
    Response.Write("<br />");
}
// Get permutations
private static IList<IList<T>> Permutations<T>(IList<T> list)
{
    List<IList<T>> perms = new List<IList<T>>();

    // If the list is empty, return an empty list.
    if (list.Count == 0)
    {
        return perms;
    }

    // This is a loop method to get the factorial of an integer
    int factorial = 1;
    for (int i = 2; i <= list.Count; i++)
    {
        // shortcut for: factorial = factorial * i;
        factorial *= i;
    }

    for (int v = 0; v < factorial; v++)
    {
        //List<T> s = new List<T>(list);
        List<T> s = new List<T>(list);

        int k = v;
        for (int j = 2; j <= list.Count; j++)
        {
            int other = (k % j);
            T temp = s[j - 1];
            s[j - 1] = s[other];
            s[other] = temp;

            k = k / j;
        }
        perms.Add(s);
    }

    return perms;
}
我好像把自己画进了一个角落。我可以想出一些解决方案,但它们看起来很混乱,所以我想我应该问问专家们

编辑

有人能想到为什么这不是个好主意吗

而不是修改堆上的对象(并影响每个可能路由中的每个点):

使用此选项,它只会创建类的新实例:

TPoint oTPoint = new TPoint(lstPermutations[0][0].id, new TData(10, 20));
lstPermutations[0][0] = oTPoint;

如果将TData设为结构,则它将按值而不是按引用进行复制。否则,您将不得不创建一个复制值的浅层克隆。

为什么不通过删除
访问器使简单的
TData
类型不可变,这样它是按值复制还是按引用复制就没有多大关系了。它可能在功能上等同于
元组


对象是存储在堆上还是其他地方可能并不重要。如果您决定使对象不可变,那么自然会将其设置为
结构
,但是
类也可以。

在初始化TPoint之前声明TData怎么样。这两者都会引用同一个对象,这也是我喜欢C#胜过Java的原因之一。您不能在Java中定义新的值类型。我希望在标记为
Java
的问题中看到相同的注释。可变(可修改,参见问题标题)对象和按值复制语义的组合可能会非常混乱。在你做出决定之前,在“为什么可变结构是邪恶的”上搜索堆栈溢出的线程。谢谢大家的回复。我还有一个问题(关于一个可能的解决方案),我已经在原始问题的底部添加了这个问题。@BrentBarbata是的,你的新解决方案也可以:)由于结构在C语言中并不常见,所以它可能更容易混淆#
lstPermutations[0][0].oTData.distance = 10;
lstPermutations[0][0].oTData.minutes = 20;
TPoint oTPoint = new TPoint(lstPermutations[0][0].id, new TData(10, 20));
lstPermutations[0][0] = oTPoint;