2012-06-26 121 views
2

比方说,我有这些类层次结构:在这种情况下,我可以避免反思吗?

public abstract class Parent { 
} 

public class A : Parent { 
    public void Update() { } 
} 

public class B : Parent { 
    public void Update() { } 
} 

public class C : Parent { 
    public void Update() { } 
    public void Update(bool force) { } 

} 

正如你所看到的,Parent所有后代有一个更新方法,不带参数。

我想创建一个实用程序类,它可以与任何种类的Parent对象一起使用,并在过程结束时调用Update。我相信Update方法将被执行,所以我写了这个代码:

public class ParentUtilities { 
    private static readonly Dictionary<Type, MethodInfo> g_UpdateMethods = new Dictionary<Type, MethodInfo>{ 
     { typeof(A), typeof(A).GetMethod("Update", new Type[] {})}, 
     { typeof(B), typeof(B).GetMethod("Update", new Type[] {})}, 
     { typeof(C), typeof(C).GetMethod("Update", new Type[] {})} 
    }; 

    public static void DoSomething(Parent p) 
    { 
      CalculateTheMeaningOfTheLife(p);    

      g_UpdateMethods[p.GetType()].Invoke(p, null); 
    } 
} 

由于我没有跨类层次(这是一个第三方组件)控制。我只能改变实用程序类。我怎样才能避免这种调整?

由于我坚持使用.Net 3.5 SP1,我无法使用动态。

+0

什么替代? – marko

+4

正如我所说的,我无法控制类层次结构(它来自第三方程序集)。 Parent和Descendants类是在第三方程序集中,但我的实用程序类来自我正在编写的代码。 –

+0

您可以构建委托来避免反射的调用。 – leppie

回答

1

如果只是一个已知的,(非常)小集合的子类,那么你可以做这样的事情:

public class ParentUtilities 
{ 
    public static void DoSomething(Parent p) 
    { 
     CalculateTheMeaningOfTheLife(p); 

     var a = p as A; 
     if (a != null) 
     { 
      a.Update(); 
      return; 
     } 

     var b = p as B; 
     if (b != null) 
     { 
      b.Update(); 
      return; 
     } 

     var c = p as C; 
     if (c != null) 
     { 
      c.Update(); 
      return; 
     } 
    } 
} 
+0

我开始想,这可能是最简单的解决方案(有实际3直接后代) –

5

一两件事你可以不接触这些类做的就是创建自己的接口IUpdateable,然后创建一个属于自己的新的并行层次结构中

interface IUpdateable 
{ 
    void Update(); 
} 

public class A : Original.A, IUpdateable {} 

如果你就可以使用自己的叶类,而不是原始的,您可以将该方法编写为接受IUpdateable参数。但同时消耗自己的类也不是很困难的(usingalias directives可以帮助),生产他们也不是那么容易(你需要每次调用创建的原始类的所有实例的原始库后干预的自定义代码,如果该实例键入为Parent,您已回到原点)。

不要忘记逼迫原始代码的作者看到。

+0

在我非常简单的例子中,这应该是完美的。然而,实际上,我访问几十个属性,方法等,这将需要自动换行的每个属性,或发布内部原有答:这将创造更多的问题,它会解决,我认为 –

+0

@SteveB:你不要” t实际上需要包装任何东西。只需定义接口就足够了,实现者将是另外的“空”类。 – Jon

+1

请注意,如果你是实例化A,B和C类的人,那么这只会起作用。如果它们中的任何一个是通过工厂方法或类似方法创建的,则这将失败。 – AhHatem

0

创建一个名为UpdatableParent一个临时类,还带有一个Update()方法,并从中获得来自它的所有其他类。然后使用UpdateableParent作为DoSomething()参数的类型。

+0

我不能改变既不是父类,也没有后裔(A,B,C) –

2

您可以创建一个定义良好的接口实现的包装类。

使用

class Program 
{ 
    static void Main(string[] args) 
    { 
     A a = new A(); 
     IUpdatable wrapper = new AWrapper(a); 
     wrapper.Update(); // prints A.Update 
    } 
} 

包装类和接口

interface IUpdatable 
{ 
    void Update(); 
} 


public abstract class Parent { } 

public class A : Parent 
{ 
    public void Update() 
    { 
     Console.WriteLine("A.Update"); 
    } 
} 

public class AWrapper : IUpdatable 
{ 
    public A Inner { get; private set; } 
    public AWrapper(A a) 
    { 
     Inner = a; 
    } 

    public void Update() 
    { 
     Inner.Update(); 
    } 
} 
+0

这个代码将要求所有来电到DoSomething方法创建一个包装实例,而不是简单地传递原始对象。我可以接受实用方法中的一些复杂性,但不是来自调用代码(毕竟这是一种实用方法,目的是简化事情) –

相关问题