在 C# 中,删除对象的 Action 会发生什么?

In C#, what will happen for an removed object's Action?

我想为我的 Class TreeNode 做一个深拷贝。这是我的代码:

    public TreeNode(TreeNode node, GUIStyle inPointStyle, GUIStyle outPointStyle, Action<ConnectionPoint> OnClickInPoint, Action<ConnectionPoint> OnClickOutPoint)
{
    this.rect = new Rect(node.rect);
    this.style = new GUIStyle(node.style);
    this.inPoint = new ConnectionPoint(this, ConnectionPointType.In, inPointStyle, OnClickInPoint);
    this.outPoint = new ConnectionPoint(this, ConnectionPointType.Out, outPointStyle, OnClickOutPoint);
    this.defaultNodeStyle = new GUIStyle(node.defaultNodeStyle);
    this.selectedNodeStyle = new GUIStyle(node.selectedNodeStyle);
    this.allDecorations = new List<GameObject>(node.allDecorations);
    this.objs = new Dictionary<GameObject, IndividualSettings>(node.objs);
    this.name = String.Copy(node.name);
    this.RemoveClonedObj = new Action(node.RemoveClonedObj);
    this.OnChangeView = new Action<TreeNode>(node.OnChangeView);
    this.OnRemoveNode =  new Action<TreeNode>(node.OnRemoveNode);
    this.OnCopyNode = new Action<TreeNode>(node.OnCopyNode);
    this.PreviewTree = new Action<TreeNode, bool> (node.PreviewTree);
}

然而,骑士给了我警告:

Rider好像在说我的"new"没有意义。 如果我按照 Rider 的指示,使用 this.RemoveClonedObj = node.RemoveClonedObj; 删除原始 TreeNode 后我复制的 TreeNode 的 Actions 会发生什么?它们也会被移除吗?如果是,为什么Rider给我这样的警告?

不要link彼此实例方法。这将导致内存泄漏。

即使删除了原始节点并且您的代码不再需要该节点,由于来自副本的引用,原始实例仍将存在于内存中并且不会被垃圾收集。

我怀疑这不是你想要的,为此测试代码

class Program
{
    static void Main(string[] args)
    {
        First t = new First();
        Second s = new Second();
        t.Print = s.TestMethod;
        s.test = "change";
        s = null;
        t.Print("Hell"); // can debug and see that the function call goes through and string test is = "change"
    }
}

public class First
{
    public string s;
    public Action<string> Print;
}
public class Second
{
    public string test = "created";
    public void TestMethod (string test)
    {
        var res = "hello" + test + test;
    }
}

要么你在节点上的方法应该是 Node 对象的一部分,这样你就不必将它们分配给新节点,要么它们应该在一个单独的 class 中,最好是静态的,这样创建新节点不会导致内存问题。

在C# 2.0及以上版本中,以下代码是等价的(DelegateType顾名思义是委托类型):

newDelegate = new DelegateType(oldDelegate);
newDelegate = oldDelegate;

(见MSDN - How to: Declare, Instantiate, and Use a Delegate (C# Programming Guide)

此外,Microsoft 指定(参见 here)此类操作将始终创建 DelegateType 新实例,它具有与oldDelegate。它们不引用同一个对象(不要被 = 赋值混淆):

The binding-time processing of a delegate_creation_expression of the form new D(E), where D is a delegate_type and E is an expression, consists of the following steps:

  • If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (Method group conversions) from E to D.

  • If E is an anonymous function, the delegate creation expression is processed in the same way as an anonymous function conversion (Anonymous function conversions) from E to D.

  • If E is a value, E must be compatible (Delegate declarations) with D, and the result is a reference to a newly created delegate of type D that refers to the same invocation list as E. If E is not compatible with D, a compile-time error occurs.

所以关于你的问题

What will happen for my copyed TreeNode's Actions aftering removing the orginal TreeNode? Will they be removed as well?

他们不会有事的。它们不会被删除。


顺便说一句,由于您正在尝试对树节点进行深拷贝,我怀疑这是否是正确的方法。尽管您已经创建了委托的新实例,但与其关联的 class 实例(将调用成员方法的实例)保持不变。