我能否检测到我是否已将新对象作为参数?

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),并且该列表包含两个项目.鲍勃可以作为被访问bobpeople[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可以将其父级知道为其状态的一部分.这与"新"或不是"新"不同 - 例如,你可以进行"分离"操作.根据对象的真实硬性状态来定义条件比使用"新"这样的粗俗术语更有意义.


Rya*_*ndy 6

是的,有办法做到这一点.

有点.

如果将参数ref设为参数,则必须将现有变量作为参数.你做不到这样的事情:

DoSomething(ref new Customer());
Run Code Online (Sandbox Code Playgroud)

如果这样做,您将收到错误"ref或out参数必须是可赋值变量".

当然,使用ref还有其他含义.但是,如果您是编写该方法的人,则无需担心它们.只要你不在方法中重新分配ref参数,无论你是否使用ref都不会有任何区别.

我不是说这是好的风格,必然.你不应该使用ref或out,除非你真的,真的需要并且没有其他办法去做你正在做的事情.但使用ref将使您想要做的工作.


Jos*_*ola 5

不.如果有某些原因你需要这样做,你的代码就有不正确的架构.

  • 如果它没有多大意义那么你为什么要编写那些代码呢?究竟. (6认同)