【问题标题】:Should a input object be cloned if it is the return value?如果输入对象是返回值,是否应该克隆输入对象?
【发布时间】:2019-05-14 17:31:49
【问题描述】:

当你有一个方法比如

public static T[] GetZeroArrayIfNot<T>(this T[] array)
{
   if (array == null)
   {
     throw new ArgumentNullException("array");
   }
   else if (array.Length == 0)
   {
       return //array or (array.Clone() as T[])?
   }
   return new T[0];
}

或类似的东西

public static int HundredOrLess(int num)
{
    if (num <= 100)
    {
        return //num or ((int num2 = num) => (return num2)) doubt this one matters.
    }
    return 100;
}

public static List<T> ReturnItself<T>(List<T> list)
{
   return //list or (list.Clone() as List<T>);
}

如果输入被返回,没有任何改变,它可以像它本身一样被返回,还是应该被克隆并作为返回类型返回?

【问题讨论】:

  • 这取决于需求,您是要克隆数组(及其对象)还是要更改现有数组?
  • 谁知道呢。取决于您的方法的逻辑/目的类型。不要问我们,问问你自己;-)
  • 返回零元素数组的指针并不重要,因为要添加一个元素,您必须创建一个新数组,因此修改一个元素不会影响另一个。如果这是List&lt;T&gt;,那就另当别论了。
  • 方法名RemoveFirstElement 暗示输入应该至少有一个元素,如果没有,应该抛出异常。否则,您应该更改方法的名称以反映实际功能。然后我敢打赌,如何处理克隆问题将是非常明显的。 ??????
  • 软件开发人员倾向于从字面上理解。这可能只是一个示例,但此示例的答案可能与其他示例的答案不同。

标签: c# clone return-value


【解决方案1】:

因为你的方法签名是这样的:

public static T[] RemoveFirstElement<T>(this T[] array)

我会假设这总是会返回一个 new 数组。因为你总是要写:

var myArray = SomeArray.RemoveFirstElement();

您不会期望myArray 现在会指向与SomeArray 完全相同的对象。如果您希望它始终对现有数组进行操作,您的方法签名将是:

public static void RemoveFirstElement<T>(this T[] array)

这样写:

var myArray = SomeArray.RemoveFirstElement();

会导致编译时错误。很明显,看到:

SomeArray.RemoveFirstElement();

将在原地运行。

【讨论】:

    【解决方案2】:

    长度为零的数组是不可变的,因此无需克隆即可安全返回。

    要从非空数组中删除一个元素,无论如何都需要克隆它,因为数组的长度不能改变。

    public static T[] RemoveFirstElement<T>(this T[] array)
    {
       if (array == null)
       {
         throw new ArgumentNullException(nameof(array));
       }
       else if (array.Length == 0)
       {
           return array;
       }
       else
       {
           return array.Skip(1).ToArray();
       }
    }
    

    【讨论】:

    • 好的,那么如果它是其他方法,例如检查值是否大于 100,如果大于 100,则返回 100,那么如果输入小于或等于 100,该怎么办?可以自己退货吗?
    • 返回值的情况(如int)也不同,因为数组是引用类型,因此返回原始值与返回克隆可能是不同的事情。对于值类型,它根本不重要。即使您“返回”参数,您并没有真正返回输入 - 您返回的新 int 与输入的值相同。
    • @ScottHannen 谢谢,这就是我一直在寻找的答案,谢谢你为我解决这个问题。
    • 我很感激,但是为了分叉,我只提供了评论,而不是答案。 (更多的是字面意思。)
    • @ScottHannen 无论如何,非常感谢。另外我认为您应该能够提交该评论作为答案,我编辑了这个问题并且它更“全面”。
    【解决方案3】:

    这是我对新示例的看法:

    public static T[] GetZeroArrayIfNot<T>(this T[] array)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        else if (array.Length == 0)
        {
            return array;
            // because the name of the method implies that a zero-length array
            // should be treated differently than a non-zero-length array
        }
        return new T[0];
    }
    
    public static int HundredOrLess(int num)
    {
        if (num <= 100)
        {
            return num;
            // It doesn't matter. The caller is not affected either way
            // because num is an immutable value type passed by value
        }
        return 100;
    }
    
    public static List<T> ReturnItself<T>(List<T> list)
    {
        return list; // Because the method name says so
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-24
      • 2016-01-23
      • 2017-01-06
      • 2015-02-22
      • 2011-07-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-06
      • 1970-01-01
      相关资源
      最近更新 更多