精简版
对于那些没有时间阅读下面我对这个问题的推理的人:
是否可以对方法的参数实现“仅新对象”或“仅现有对象”策略?
长版
有很多将对象作为参数的方法,并且该方法是否具有“全部自身”的对象并不重要。例如:
var people = new List<Person>();
Person bob = new Person("Bob");
people.Add(bob);
people.Add(new Person("Larry"));
此处List<Person>.Add
方法采用了“现有的” Person
(Bob)和"new"的Person
(Larry),并且列表包含这两项。 Bob可以使用bob
或people[0]
进行访问。可以将Larry作为people[1]
进行访问,如果需要,可以将其缓存并随后作为larry
(或其他任何方式)进行访问。好的。但有时确实不应将方法传递给新对象。以
Array.Sort<T>
为例。以下内容并没有多大意义:Array.Sort<int>(new int[] {5, 6, 3, 7, 2, 1});
上面所有代码所做的就是获取一个新数组,对其进行排序,然后将其忘记(因为在Array.Sort<int>
退出后其引用计数达到零,因此,如果我没有记错的话,将对垃圾箱进行排序)。因此,Array.Sort<T>
希望将“现有”数组作为其参数。可以想到还有其他可能期望"new"对象的方法(尽管我通常认为拥有这样的期望将是一个设计错误)。一个不完美的例子是这样的:
DataTable firstTable = myDataSet.Tables["FirstTable"];
DataTable secondTable = myDataSet.Tables["SecondTable"];
firstTable.Rows.Add(secondTable.Rows[0]);
就像我说的那样,这不是一个很好的例子,因为DataRowCollection.Add
实际上并不需要一个新的DataRow
;但它确实希望DataRow
不属于DataTable
。因此,上面代码中的最后一行将不起作用;它必须是:firstTable.ImportRow(secondTable.Rows[0]);
无论如何,这是针对我的问题的大量设置,即:是否可以对方法的参数强制执行“仅新对象”或“仅现有对象”策略(无论是在其定义中(也许是某些情况下)自定义属性(我不知道)还是在方法本身内(也许是通过反射,尽管即使有可能我也会回避)?如果不是这样,那么关于如何实现此目标的任何有趣想法都将受到欢迎。例如,我假设如果有某种方法可以获取给定对象的GC引用计数,则可以在方法开始时立即告诉您是否收到了新对象(假设您正在处理引用类型) ,当然-这是与此问题相关的唯一情况)。
编辑:
越长的版本越长。
好吧,假设我有一些方法可以选择接受
TextWriter
来输出其进度或您拥有了什么:static void TryDoSomething(TextWriter output) {
// do something...
if (output != null)
output.WriteLine("Did something...");
// do something else...
if (output != null)
output.WriteLine("Did something else...");
// etc. etc.
if (output != null)
// do I call output.Close() or not?
}
static void TryDoSomething() {
TryDoSomething(null);
}
现在,让我们考虑一下可以调用此方法的两种不同方式:string path = GetFilePath();
using (StreamWriter writer = new StreamWriter(path)) {
TryDoSomething(writer);
// do more things with writer
}
或者:TryDoSomething(new StreamWriter(path));
嗯...看来这是个问题,不是吗?我已经构造了一个StreamWriter
,它实现了IDisposable
,但是TryDoSomething
不会假定知道它是否具有对其output
参数的独占访问权。因此,对象要么过早处置(在第一种情况下),要么根本不处置(在第二种情况下)。我并不是说这肯定是一个很棒的设计。乔什·斯托多拉(Josh Stodola)也许是正确的,从一开始这就是一个坏主意。无论如何,我之所以问这个问题,主要是因为我很好奇这种事情是否可能发生。看起来答案是:并非如此。
最佳答案
不,基本上。
两者之间确实没有区别:
var x = new ...;
Foo(x);
和
Foo(new ...);
实际上,有时您可能会出于调试目的而在两者之间进行转换。
请注意,在
DataRow
/DataTable
示例中,还有另一种方法-DataRow可以知道其父级作为其状态的一部分。这与是否"new"不是一回事-例如,您可以进行“分离”操作。相对于诸如“new”之类的粗俗术语,用对象的真实的硬性状态来定义条件要有意义得多。