我可以从C#委托返回对新对象实例的引用吗?
我正在学习/试验C#中的一些功能模式,遇到了一个无法解释的问题。我相信这是一个简单的答案(我希望如此),但我很难看到它。很可能与闭包等有关,而我无法跳出盒子,这就对我隐瞒了答案 这是我的实验:我试图从函数委托中返回一个特定类的全新实例我可以从C#委托返回对新对象实例的引用吗?,c#,anonymous-delegates,C#,Anonymous Delegates,我正在学习/试验C#中的一些功能模式,遇到了一个无法解释的问题。我相信这是一个简单的答案(我希望如此),但我很难看到它。很可能与闭包等有关,而我无法跳出盒子,这就对我隐瞒了答案 这是我的实验:我试图从函数委托中返回一个特定类的全新实例 public class Foo{ string A { get; set ; } } static void Main( string[] args ){ // the delegate... Func<Foo,bool>
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{get;set;}
}
静态void Main(字符串[]参数){
//代表。。。
Func someFunc=o=>{
o=newfoo{A=“o的新实例?”};
返回true;
};
Foo-Foo=null;//希望通过委托替换此
var myFunc=someFunc;
var结果=myFunc(foo);
if(foo==null)
Console.WriteLine(“foo未更改:-(”);
其他的
Console.WriteLine(foo.A);//希望“一个新的o实例?”
当然,我只是在输出中得到“foo unchanged:-()。
我在测试中做了一个小小的改动,传入了一个非null的Foo实例,并修改了属性“a”(vs返回一个新实例),效果很好(也就是说,我可以像向函数传递对象引用时所期望的那样改变一个现有对象),但我似乎无法从委托中获得一个新实例
那么?我只是在代码中做错了什么吗?这能做到吗?我很想了解为什么这不起作用。您可以将
Foo
作为lambda表达式的返回值返回:
Func<Foo> someFunc = o =>
{
return new Foo { A = "A new instance of o?" };
};
或者,如果您真的确定需要,您可以使用以下命令声明自己的自定义委托:
委托TResult FuncOut(out T arg);
FuncOut someFunc=(out Foo)=>
{
o=newfoo{A=“o的新实例?”};
返回true;
};
富富,;
var结果=someFunc(输出foo);
但我不建议这样做。您正在将Foo
对象的引用(即地址)传递给您的委托。该地址被分配给委托的参数o
(将其视为局部变量)。当您更改委托中的Foo
对象时,您将转到引用的对象并更改该地址上的内容。这就是对象更改的原因
但当您为委托的局部变量(即参数)分配新地址时,则您只是丢失了传递给委托的原始
Foo
对象的地址。赋值后,局部变量只保留新Foo
对象的地址。它不影响调用方的Foo
变量,调用方的Foo
变量仍保留另一个地址。形式参数o
是Foo值的副本ode>;突变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 );
如果你只想变异一个变量,那么就变异这个变量。如果你只想执行一个副作用,就不需要在委托中传入或传出任何东西
我注意到你说你在试验函数模式。记住,函数编程不鼓励变量变异,所以你可能走上了错误的道路。我同意!没有“out”参数;-)因此,返回元组中的对象是我可能会采用的方式。我认为lazyberezovsky给了我一个关于“为什么”的线索,但我将此标记为答案,因为您给了我“什么”和我需要的解决方法。谢谢,这非常有意义。最终,这回答了我的基本问题,即为什么我的测试不起作用(希望我能给出部分答案)。我想我错过了一堂关于对象引用的基础课,这门课被委托方面掩盖了。事实上,我的测试即使使用传统的(即非委托)方法也不起作用。感谢您的帮助!在您的示例中(使用ints),我知道这对值类型是适用的,但是如果x
和y
是引用类型,那么在y=x
语句之后,我现在不是在处理对同一对象的两个引用吗?我通过y
所做的任何更改都会影响x
。我错过了什么吗?哦,我知道有人会抓住我的功能注释;-)我明白,在我沿着这条功能道路前进的过程中,突变并不是答案。捕捉得好,谢谢提醒。@ROBCOM 88:如果x
和y
用字段z
引用同一对象,那么x.z
和y.z
引用同一字段,但x
和y
不要引用e彼此。它们都指向同一个对象。@robcom88:这样想。你有两个抽屉,标签是x
和y
。在x
中有一张纸,上面写着123芝麻街
。当你说y=x;
时,意味着拿出复印机,放第二张纸,上面写着ode>123芝麻街
改为y
x
和y
现在指的是同一所房子,但如果你把x
中的那张纸扔掉,换成写着1600宾夕法尼亚大道
的纸,这不会改变抽屉y
的内容只是另一种价值。
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);
int x = 1;
int y = x;
y = 2;
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 );