【问题标题】:In C#, what will happen for an removed object's Action?在 C# 中,被移除对象的 Action 会发生什么?
【发布时间】:2019-09-30 06:20:12
【问题描述】:

我想为我的类 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 似乎在说我的“新”毫无意义。 如果我按照 Rider 的指示,使用this.RemoveClonedObj = node.RemoveClonedObj; 删除原始 TreeNode 后,我复制的 TreeNode 的操作会发生什么?它们也会被删除吗?如果是这样,为什么 Rider 会给我这样的警告?

【问题讨论】:

  • 你能不能也给我们看一下TreeNode这个类?
  • 似乎node.PreviewTree 已经属于Action&lt;TreeNode,bool&gt; 类型,因此从现有的操作创建新操作是多余的。在大多数情况下,this 也是多余的,除非您使用的参数或局部变量与类字段的名称完全相同。只需使用PreviewTree = node.PreviewTree;

标签: c# unity3d rider


【解决方案1】:

在 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 相同的调用列表。它们不引用同一个对象(不要被 = 赋值混淆):

new D(E) 形式的 delegate_creation_expression 的绑定时处理,其中 D 是 delegate_type,E 是表达式,包括以下步骤:

  • 如果 E 是方法组,则委托创建表达式的处理方式与从 E 到 D 的方法组转换(方法组转换)相同。

  • 如果 E 是匿名函数,则委托创建表达式的处理方式与从 E 到 D 的匿名函数转换(Anonymous function conversions)相同。

  • 如果 E 是一个值,则 E 必须与 D 兼容(委托声明),结果是对新创建的 D 类型委托的引用,该委托引用与 E 相同的调用列表。如果 E 与 D 不兼容,则会发生编译时错误。

所以关于你的问题

删除原始 TreeNode 后,我复制的 TreeNode 的操作会发生什么?它们也会被删除吗?

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


顺便说一句,由于您正在尝试制作树节点的深层副本,我怀疑这是否是正确的方法。虽然您已经创建了委托的新实例,但与之关联的类实例(将调用成员方法的实例)保持不变。

【讨论】:

    【解决方案2】:

    不要将实例方法相互链接。这会导致内存泄漏。

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

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

    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 对象的一部分,这样您就不必将它们分配给新节点,或者它们应该在单独的类中,最好是静态的,这样新节点的创建就不会导致内存问题。

    【讨论】:

      猜你喜欢
      • 2022-06-27
      • 2011-08-06
      • 2014-06-19
      • 2011-11-27
      • 2021-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多