Dan*_*Tao 8 .net c# parameters reference new-operator
对于那些没有时间阅读我对以下问题的推理的人:
有没有办法为方法的参数强制执行"仅新对象"或"仅现有对象"的策略?
有很多方法将对象作为参数,并且方法是否具有对象"all to their"并不重要.例如:
var people = new List<Person>();
Person bob = new Person("Bob");
people.Add(bob);
people.Add(new Person("Larry"));
Run Code Online (Sandbox Code Playgroud)
这里该List<Person>.Add方法采用了"现有" Person(Bob)以及"新" Person(Larry),并且该列表包含两个项目.鲍勃可以作为被访问bob或people[0].Larry可以作为people[1]并且如果需要,可以在larry此后作为(或其他)进行缓存和访问.
好的.但有时一个方法确实不应该传递给新对象.举个例子吧Array.Sort<T>.以下内容并没有多大意义:
Array.Sort<int>(new int[] {5, 6, 3, 7, 2, 1});
Run Code Online (Sandbox Code Playgroud)
所有上面的代码都是采用一个新的数组,对它进行排序,然后忘记它(因为它的引用计数在Array.Sort<int>退出后达到零,因此排序的数组将被垃圾收集,如果我没有记错的话).因此,Array.Sort<T> 期望 "现有"数组作为其参数.
可以想象有其他方法可以期待 "新"对象(尽管我通常认为这样的期望会是设计错误).一个不完美的例子是:
DataTable firstTable = myDataSet.Tables["FirstTable"];
DataTable secondTable = myDataSet.Tables["SecondTable"];
firstTable.Rows.Add(secondTable.Rows[0]);
Run Code Online (Sandbox Code Playgroud)
正如我所说,这不是一个很好的例子,因为DataRowCollection.Add实际上并没有真正期待一个新的 DataRow,确切的; 但它确实期望一个DataRow不属于a的DataTable.所以上面代码中的最后一行不起作用; 它需要是:
firstTable.ImportRow(secondTable.Rows[0]);
Run Code Online (Sandbox Code Playgroud)
无论如何,这是我的问题的很多设置,它是:有没有办法在方法的参数中强制执行"仅新对象"或"仅现有对象"的策略,或者通过一些自定义属性我不知道或者在方法本身内(也许是通过反思,虽然我可能会回避它,即使它可用)?
如果没有,任何有关如何实现这一目标的有趣想法都将受到欢迎.例如,我想如果有某种方法来获取给定对象的GC引用计数,您可以立即告诉方法的开头是否已收到新对象(假设您正在处理引用类型)当然 - 这是这个问题无论如何都是相关的唯一场景.
编辑:
版本越长越长.
好吧,假设我有一些方法可以选择接受a 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);
}
Run Code Online (Sandbox Code Playgroud)
现在,让我们考虑两种不同的方法来调用此方法:
string path = GetFilePath();
using (StreamWriter writer = new StreamWriter(path)) {
TryDoSomething(writer);
// do more things with writer
}
Run Code Online (Sandbox Code Playgroud)
要么:
TryDoSomething(new StreamWriter(path));
Run Code Online (Sandbox Code Playgroud)
嗯......看来这会造成问题,不是吗?我构建了一个StreamWriter实现的IDisposable,但TryDoSomething不会假设它是否具有对其output参数的独占访问权.因此,对象要么过早地放置(在第一种情况下),要么根本不放置(在第二种情况下).
我不是说这将是一个伟大的设计,必然.也许Josh Stodola是对的,这从一开始就是一个坏主意.无论如何,我问这个问题主要是因为我只是好奇这样的事情是否可能.看起来答案是:不是真的.
Jon*_*eet 10
不,基本上.
两者之间真的没什么区别:
var x = new ...;
Foo(x);
Run Code Online (Sandbox Code Playgroud)
和
Foo(new ...);
Run Code Online (Sandbox Code Playgroud)
实际上有时您可能会在两者之间进行转换以进行调试.
请注意,在DataRow/ DataTable示例中,有一种替代方法 - DataRow可以将其父级知道为其状态的一部分.这与"新"或不是"新"不同 - 例如,你可以进行"分离"操作.根据对象的真实硬性状态来定义条件比使用"新"这样的粗俗术语更有意义.
是的,有办法做到这一点.
有点.
如果将参数ref设为参数,则必须将现有变量作为参数.你做不到这样的事情:
DoSomething(ref new Customer());
Run Code Online (Sandbox Code Playgroud)
如果这样做,您将收到错误"ref或out参数必须是可赋值变量".
当然,使用ref还有其他含义.但是,如果您是编写该方法的人,则无需担心它们.只要你不在方法中重新分配ref参数,无论你是否使用ref都不会有任何区别.
我不是说这是好的风格,必然.你不应该使用ref或out,除非你真的,真的需要并且没有其他办法去做你正在做的事情.但使用ref将使您想要做的工作.