一. 引子(Introduction)
大概在半年前,曾与公司某个同事争吵一个循环引用的问题。当时吵的面红耳赤,这几天想把当时,为了吵赢那次问题,做的功课给写下来。
然后是,以前公司部门经理吹嘘某部门大佬在移交客户代码中解决循环引用的问题图镇楼。我就不懂为什么他写的这样的代码都不会被客户反馈,而我写代码就算自己没写错,标准版也会报一堆错误,真的是太悲伤了。
我其实一直想不通的是,为什么能写出这样代码的人,不但每次在我被批评的时候,都拿出来讲成榜样给我听,A数C数太多了。
话不多说,来看看的如何解决。
二. 目录(Contents)
1. 引入场景
2. 使用委托解决
3. 使用反射解决
4. 使用接口解决
5. 示例工程下载
三. 场景(Situation)
在解决问题之前,我先引入一个场景。假设有一个类A,它里面有两个方法一个是MethodA_One()而另外一个是MethodA_Two()。于此同时,有另外一个类B,它里面有两个方法MethodB_One()个MethodB_Two()。
遇到这样一个业务场景类A中的MethodA_One()要调用类B中的MethodB_One(),而类B中的MethodB_Two()要调用A中的MethodA_Two()中的方法。
明显可知,如果类A和类B分别在两个程序集中,如果彼此引用会出现循环引用的问题。那么下面的解决方法都以这个列子进行处理。
四. 使用委托解决(Using Delegate)
一般人遇到这个问题的第一反应就是委托。因为委托很像“传递一个函数指针”给另一个类,往往在类与类之间可以不通过直接的对象引用,来使用另一个类的方法。
首先让A的程序集引用B的程序集。
(1)类A代码:
public class A
{
private B innerClassB = null;
public A(B classB)
{
classB.MethodDelegate = (Action)this.MethodA_Two;
this.innerClassB = classB;
}
public void MethodA_One()
{
Console.WriteLine("Class A: MethodA_One");
if(this.innerClassB!=null)
{
innerClassB.MethodB_One();
}
}
public void MethodA_Two()
{
Console.WriteLine("Class A: MethodA_Two");
}
}
(2)类B的代码:
public class B
{
public Action MethodDelegate = null;
public void MethodB_One()
{
Console.WriteLine("Class B: MethodB_One");
}
public void MethodB_Two()
{
Console.WriteLine("Class B: MethodB_Two");
if(this.MethodDelegate!=null)
{
MethodDelegate();
}
}
}
(3)上端调用:
B classB = new B();
A classA = new A(classB);
classA.MethodA_One();
classB.MethodB_Two();
五. 使用反射解决(Using Reflection)
反射也不失为一个很好的方法。在一些项目中常用反射来进行解耦(解除类与类之间中引用)。当然使用反射的话,不但会造成一定的性能的损失,而且会让代码变的更加的难懂(本来简单的代码变得复杂了)的。
首先让A的程序集引用B的程序集。
(1)在B的程序集中增加接口IMethod:
public interface IMethod
{
void MethodA_One();
void MethodA_Two();
}
(2)类A代码:
public class A : IMethod
{
private B innerClassB = null;
public A(B classB)
{
this.innerClassB = classB;
}
public void MethodA_One()
{
Console.WriteLine("Class A: MethodA_One");
if (innerClassB != null)
{
innerClassB.MethodB_One();
}
}
public void MethodA_Two()
{
Console.WriteLine("Class A: MethodA_Two");
}
}
(3)类B代码:
public class B
{
public void MethodB_One()
{
Console.WriteLine("Class B: MethodB_One");
}
public void MethodB_Two()
{
Console.WriteLine("Class B: MethodB_Two");
string path = AppDomain.CurrentDomain.BaseDirectory + "ClassALib.dll";
Assembly assembly = Assembly.LoadFrom(path);
IMethod classA = null;
if (assembly!=null)
{
Type type = assembly.GetType("ClassALib.A");
if (type != null)
{
classA = Activator.CreateInstance(type, this) as IMethod;
}
}
if(classA!=null)
{
classA.MethodA_Two();
}
}
}
(4)上端调用:
B classB = new B();
A classA = new A(classB);
classA.MethodA_One();
classB.MethodB_Two();
六. 使用接口解决(Using Interface)
这个是比较简单而且是比较推荐的做法。
首先让A的程序集引用B的程序集。
(1)在B的程序集中增加接口IMethod:
public interface IMthod
{
void MethodA_Two();
}
(2)类A代码:
public class A:IMthod
{
private B innerClassB = null;
public void GetClassB(B classB)
{
this.innerClassB = classB;
}
public void MethodA_One()
{
Console.WriteLine("Class A: MethodA_One");
if(innerClassB!=null)
{
innerClassB.MethodB_One();
}
}
public void MethodA_Two()
{
Console.WriteLine("Class A: MethodA_Two");
}
}
(3)类B代码:
public class B
{
private IMthod innerClassA = null;
public B(IMthod classA)
{
this.innerClassA = classA;
}
public void MethodB_One()
{
Console.WriteLine("Class B: MethodB_One");
}
public void MethodB_Two()
{
Console.WriteLine("Class B: MethodB_One");
if(innerClassA!=null)
{
innerClassA.MethodA_Two();
}
}
}
(4)上端调用:
A classA = new A();
B classB = new B(classA);
classA.GetClassB(classB);
classA.MethodA_One();
classB.MethodB_Two();
七. 示例工程下载(Download Project)