2013-06-30 20 views
5

在传统的C#代码一些代码审查我一直在做最近我已经看到了很多的例子是这样的:传递父对象作为父对象交互的参考邪恶的做法?

class ManagerParentClass 
{ 
    public string CustomProperty{get;set;} 
    public void Log(string message); 

    void DoABunchOfTasks() 
    { 
     new SomethingService().DoSomething(this); 
    } 
} 

下列要求:

public class SomethingService 
{ 
    ManagerParentClass _manager; 

    void DoSomething(ManagerParentClass manager) 
    { 
     _manager = manager; 

     // do something 
     _manager.CustomProperty = "hello world"; 
     _manager.Log("said hello world"); 
    } 
} 

虽然这工作正常上表面上,我担心这是一种反垃圾回收模式,可能会导致垃圾回收。

这是否会打破.Net的世代垃圾回收器能够正确地清理父对象或子对象或其他消极对象?

+2

如果GC未被使用,GC将不会保留根。我认为这只是糟糕的编程。这些课程有混合的责任。奇妙的问题,但。 –

+2

父子引用在任何体面参与的对象图中都很常见。这是.NET GC的祝福。过去,我们必须使用'CopyMemory'和'ObjPtr'来打破VB6中不可宽恕的内存管理系统中的循环引用。 – tcarvin

回答

2

哦,是的,这是一个可怕的反模式。我使用的代码基础很多,这完全是疯狂的。

最大的进攻是什么?违反封装和随之而来的类之间的紧密耦合:SomethingService知道太多关于ManagerParentClass,而ManagerParentClass放弃对其自身的控制,以至于SomethingService

两个更好的选择:

  1. DoSomething()ManagerParentClass一个实例方法,这与面向对象的基本点相比保持一致,即数据结构进行了运营商
  2. SomethingService一个方法做一些计算并返回一个值,呼叫者可以将分配分配给ManagerParentClass

当然,这两个重构都涉及一个ManagerParentClass的最终游戏突变,并且从功能编程的角度来看,我会尽量避免这种情况。但没有更多的信息,我不能为此推荐一门课程。

+0

我不同意。当您使用访问者模式实现相当于一种编程语言的地方时,几乎需要做这种事情,在这种编程语言中,您要创建对包含在外部缓存或存储中的一组数据进行操作的函数。也许“总的来说”这是一个坏主意,但绝对有些情况下,看起来好像是做这种事情是绝对必要的。尝试实施具有指令的虚拟CPU,外部存储并验证外部存储是否合法,而无需执行此操作。这真的很难。 –

+0

@MikeTaber是的,我同意访问者模式的适当应用是你想要做这种事情的合理情况。但请注意,某些语言(如F#)具有取代访问者模式的功能(例如判别联合和模式匹配)。即合法需要这样做可能只是反映了语言功能的缺失。 –

+0

也许这是真的。但是这个问题是关于C#而不是F#的,并且是否将父引用传递给孩子的做法本身就是邪恶的。我认为答案更具有上下文性,并且考虑到上述例子,很难说。考虑到这个具体的例子,我认为这是一个糟糕的设计,但有时候有很好的理由这样做。这是我唯一的观点。这绝对会导致问题的一个地方是序列化,因为当对象序列化时,父引用无效。你可以考虑它,但它变得很难看。然而,它的作品... soo ... :) –

1

这实际上是一种相互分离类的体面方式 - 您写的内容看起来很像访问者模式。

你写的例子根本没有太大的内存影响,因为除了那个方法的长度之外,SomethingService并不支持ManagerParentClass。如果我们假设SomethingService会在构造或常规方法中保存这样的实例,那么它稍微复杂一点。

SomethingService持有一个对ManagerParentClass的引用,意味着ManagerParentClass将被保存在引用1)中,只要SomethingService通过引导回GC根的某些引用链保存在内存中; 2)只要SomethingService保持其对MPC的参考。

如果SS发布它的引用(null out),那么问题就解决了。如果SS本身不再被任何东西引用,则GC将知道SS可以是GCd,并且如果MPC仅由SS保持,则MPC可以依次为GCd。

+1

-1'ManagerParentClass'和'SomethingService'与这种方法显然紧密结合。如果它实际上是访问者模式,那么这与一个目的紧密耦合(OO语言弥补了缺乏判别联合),但我不相信它是(并且看起来像访问者模式,但并不完全听起来很可怕)。 –

+0

我不认为这是访问者,但其余的答案是好的。 – tcarvin