C# 递归,can';不能使嵌套的自对象为空,为什么会这样?
我试图在递归代码中更新self对象的列表,但它没有这样做,但是当通过更改值来更新对象时,效果很好C# 递归,can';不能使嵌套的自对象为空,为什么会这样?,c#,.net,recursion,C#,.net,Recursion,我试图在递归代码中更新self对象的列表,但它没有这样做,但是当通过更改值来更新对象时,效果很好 名称空间测试 { 班级计划 { 静态void Main(字符串[]参数) { 节点main=新节点(); main.Sequence=“1”; main.Id=1; main.ChildNodes.Add(新节点() { Sequence=“1.1”, Id=2 }); main.ChildNodes.Add(新节点() { Sequence=“1.2”, Id=3 }); main.ChildN
名称空间测试
{
班级计划
{
静态void Main(字符串[]参数)
{
节点main=新节点();
main.Sequence=“1”;
main.Id=1;
main.ChildNodes.Add(新节点()
{
Sequence=“1.1”,
Id=2
});
main.ChildNodes.Add(新节点()
{
Sequence=“1.2”,
Id=3
});
main.ChildNodes.Add(新节点()
{
Sequence=“1.3”,
Id=4
});
Console.WriteLine(“之前:”);
打印节点(主);
Console.WriteLine();
MakeNull(main);
控制台。WriteLine(“在:”)之后;
打印节点(主);
void MakeNull(节点)
{
foreach(节点中的变量Child.ChildNodes)
{
MakeNull(Child);
}
node.ChildNodes.RemoveAll(p=>p==null);
如果(node.ChildNodes.Count==0)
{
node.Id=5;//这正在工作
node=null;//这不是,为什么?
}
}
Console.ReadLine();
}
静态void打印节点(节点)
{
Console.WriteLine(“Id:+node.Id+”序列:+node.Sequence);
对于(int i=0;i
为什么不将整个对象设为null?因为在方法MakeNull(Node Node)中,Node成为该范围内的一个引用,从调用函数中保存“main”对象。在函数中将node设置为null,只有在该方法中将节点引用设置为null时才有效。对“main”的引用丢失(被null覆盖) 这并不意味着MakeNull(Node-Node)方法之外的“main”变为null 设置Id确实有效,因为您在用null覆盖节点引用之前设置了Id。此时,节点仍然引用“main”,我们可以获得对Id的setter的引用,然后设置其值 如果要使列表中的项为null,必须执行如下操作:main[i]=null 其他人指出,使用ref关键字应该可以做到这一点,但这仅适用于MakeNull(main)。不适用于子项。在您所做的工作中,您可能希望看到一个“null”子项列表(例如,调用ChildItem[1],然后希望看到“null”)。但事实并非如此 请参阅下面的代码片段,以了解将发生的情况:
List<Bla> a = new List<Bla>();
a.Add(new Bla());
a.Add(new Bla());
a.Add(new Bla());
void MakeNull(ref Bla a) { a = null; }
var a1 = a[1];
MakeNull(ref a1);
// MakeNull(ref a[1]); // not allowed by compiler
// MakeNull(ref a.ElementAt(1)); // not allowed by compiler
Console.WriteLine(a1); // prints nothing (null)
Console.WriteLine(a[1]); // prints "Core.App.Bla"
List a=新列表();
a、 添加(新Bla());
a、 添加(新Bla());
a、 添加(新Bla());
void MakeNull(ref Bla a){a=null;}
var a1=a[1];
MakeNull(参考a1);
//MakeNull(参考文献a[1]);//编译器不允许
//MakeNull(参考a.ElementAt(1));//编译器不允许
控制台写入线(a1);//不打印任何内容(空)
Console.WriteLine(a[1]);//打印“Core.App.Bla”
您可以通过使用lambda操作来解决此问题,该操作引用集合上的实际索引器方法或另一个setter方法:
void MakeNullAction(Action<Bla> setter) { setter(null); }
MakeNullAction((value) => a[1] = value);
Console.WriteLine(a[1]); // prints nothing (null)
void MakeNullAction(操作设置器){setter(null);}
MakeNullAction((值)=>a[1]=值);
Console.WriteLine(a[1]);//不打印任何内容(空)
将函数参数声明为引用类型时,该值将通过引用传递给函数。这意味着,当您将一个方法参数声明为typeNode
时,您将获得一个指针的副本,该指针指向传递到方法中的同一内存位置,而实际上并不是传递对象本身
void MakeNull(Node node) // <-- This is a new variable that points to the same memory location as the variable that was passed in
{
foreach (var Child in node.ChildNodes)
{
MakeNull(Child);
}
node.ChildNodes.RemoveAll(p => p == null);
if (node.ChildNodes.Count == 0)
{
node.Id = 5;
node = null;
}
}
void MakeNull(Node Node)//p==null);
如果(node.ChildNodes.Count==0)
{
node.Id=5;
node=null;
}
}
变量节点
的范围仅限于方法,因为方法参数是声明它的地方。当您在方法中将其设置为null
时,您只是在销毁指向方法内部节点
内存位置的指针,但传递到方法中的指针保持不变,因为它在调用方法时已被复制
为什么不能使整个对象为空
简而言之,因为对象不能设置为null。只能使用对象指针(变量)。您正在处理两个类型为Node
的独立对象指针,一个在方法内部,一个在方法外部
将方法内部的
节点
变量设置为null
只会破坏在方法开头创建的指针。当您拥有对内存位置的引用,并将其Id
属性更新为5
时,您使用的是对象本身,而不是对象指针。要了解发生了什么,必须知道类是引用类型。即,此类型的变量包含null
或对对象的引用。它们不包含对象本身或存储在此对象中的值
这与int
等值类型不同。这种类型的变量实际上是c
void MakeNull(ref Node node)
{
...
node = null;
...
}
MakeNull(ref main);
MakeNull(ref Child);
MakeNull(ref main);