我可以从C#委托中返回对新对象实例的引用吗?
我正在学习/试用C#中的一些功能模式,并且我碰到了一个我不能解释的凹凸。我相信这是一个简单的答案(我希望),但我很难看到它。可能与封闭等有关,我无法摆脱箱子隐藏我的答案!我可以从C#委托中返回对新对象实例的引用吗?
这里是我的实验:我想从一个函数委托中返回一个特定类的品牌新实例..
public class Foo{
string A { get; set ; }
}
static void Main(string[] args){
// the delegate...
Func<Foo,bool> someFunc = o => {
o = new Foo { A = "A new instance of o?" };
return true;
};
Foo foo = null; // was hoping to replace this via delegate
var myFunc = someFunc;
var result = myFunc(foo);
if (foo == null)
Console.WriteLine("foo unchanged :-(");
else
Console.WriteLine(foo.A); // hoping for 'A new instance of o?'
当然,我只是得到“富不变:-(”在我的输出 我在测试中做了一个细微的变化,我在非空Foo实例中传递并修改了属性“A”(vs返回一个新实例)并且工作正常(也就是说,我可以改变现有对象就像我期望将对象引用传递给函数时一样)我似乎无法从我的代理中获取新实例。
那么,我只是在代码中做错了什么?这可以完成吗?想知道为什么这不起作用。
您可以返回Foo
作为lambda表达式的返回值:
Func<Foo> someFunc = o =>
{
return new Foo { A = "A new instance of o?" };
};
或者你可以返回Tuple<bool, Foo>
如果你真的需要返回一个bool
:
或者,如果你真的真的确定你想要的,你可以声明你自己的自定义Func
-like代表与out
parameter:
delegate TResult FuncOut<T, TResult>(out T arg);
FuncOut<Foo, bool> someFunc = (out Foo o) =>
{
o = new Foo { A = "A new instance of o?" };
return true;
};
Foo foo;
var result = someFunc(out foo);
但我不会建议。
您正将Foo
对象的引用(即地址)传递给您的代理。该地址分配给委托的参数o
(将其视为本地变量)。当您在委托中更改Foo
对象时,您将要引用对象并更改该地址上的内容。这就是对象改变的原因。
但是,当您将新地址分配给代理的局部变量(即参数)时,那么您仅丢失传递到委托的原始Foo
对象的地址。赋值局部变量之后只保存新的Foo
对象的地址。它不影响调用者的foo
变量,该变量仍包含另一个地址。
好的,这很有道理。最终,这回答了我的潜在问题,为什么我的测试不起作用(希望我能给出部分答案功劳)。我认为我错过了这里的对象引用中的一个基本教训,这个引导被代表方面所模糊。事实上,即使使用传统(即非委托)方法,我的测试也不会起作用。感谢帮助! – robcom88 2013-03-16 14:57:37
形式参数o
是拷贝的值foo
;突变o
不会变异foo
。这和你说的一样:
int x = 1;
int y = x;
y = 2;
这并不改变x
。 y
是x
,而不是一个别名到x
的值的副本。
你正在过问这个问题。如果你想有一个变异本地的委托,然后只写变异本地的委托:
Foo foo = null; // was hoping to replace this via delegate
Action mutateFoo =() => { foo = new Foo() { A = "whatever"}; };
mutateFoo();
if (foo == null)
Console.WriteLine("foo unchanged :-(");
else
Console.WriteLine(foo.A);
如果你想要做的是变异的变量,然后变异的变量。如果您只是想执行副作用,则无需从委托中传入或传出任何内容。
我注意到你说你正在试验功能模式。请记住,功能性编程阻止变异突变,所以你可能会在这里走错路。
在你的例子中(使用整数),我明白这适用于_value types_,但如果'x'和'y'是_reference types_,那么在'y = x'语句之后,我现在不是处理两个引用同样的目标?我通过'y'所做的任何更改都会影响'x'。我错过了那里的东西吗? – robcom88 2013-03-16 15:10:37
哦,我知道有人会让我看到这个功能性评论;-)我明白,当我沿着这条功能性的道路前进时,突变不是答案。良好的接触和感谢提醒。 – robcom88 2013-03-16 15:11:58
@ robcom88:如果'x'和'y'指向字段为'z'的同一个对象,那么'xz'和'yz'指向同一个字段,但'x'和'y'不指向*其他*。它们都指向*相同的对象*。 – 2013-03-16 15:13:00
我同意!没有'out'parms ;-)所以,返回Tuple中的对象是我可能会去的方式。我认为lazyberezovsky给了我一个关于'为什么'的线索,但我将其标记为答案,因为你已经给了我'需要的'和''的解决方法。谢谢 – robcom88 2013-03-16 14:52:34