我可以从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>

我正在学习/试验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{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 );