2011-07-11 102 views
1

背景: 我与有许多复杂的UI组件非常大的解决方案的工作。为了进行错误跟踪,我们希望能够记录用户采取的任何操作,以便我们可以重新创建(以某种可脚本化的方式)用户在使用GUI时可能遇到的任何情况。为了实现这个目标,我们希望创建一个标准,强制任何UI组件使用的任何系统组件实现一个非常简单的接口。该接口将有Get,Set和Run方法。 (日志/脚本将由这些方法生成。)除了这些Get,Set和Run方法外,派生类的所有其他成员都是私有的。使用泛型来实现简化的对象接口

问题: 我想要一个很好的方式来实现这样一个接口,不得不承认,我正在努力解决这个问题所需的一些抽象概念。我知道如何使用对象来做到这一点,但我知道铸造对象可能很昂贵,而且解决方案不会安全。我刚开始学习泛型,似乎这可能是走下坡路的最佳途径,但我正在努力实施。以下是我正在玩的一些示例代码。为了简单起见,它并没有实际实现一个接口,但它的结构就像它需要的那样。

代码编译和运行,但我知道我不是实现这个非常好。我可能不会在Get或Set函数中使用Convert.ChangeType通过简单的对象强制转换来节省任何费用。我也在摧毁泛型应该提供的类型安全。

虽然对这个部分的任何建议,欢迎,最好的答案可能会被授予那些显示我应该如何使用泛型要正确实施此解决方案。这里是我正在玩的代码,以说明迄今为止的概念:

public class TestClass { 
public enum SetEnum { Val1, Val2 } 
public enum GetEnum { Calculated, Result } 
public enum RunEnum { Add, Subtract, Reset } 

private double Val1; 
private int Val2; 
private bool Calculated; 
private double Result; 

public void Set<T>(SetEnum member, T val) { 
    switch (member) { 
    case SetEnum.Val1: 
     Val1 = (double)Convert.ChangeType(val, Type.GetTypeCode(typeof(double))); 
     break; 
    case SetEnum.Val2: 
     Val2 = (int)Convert.ChangeType(val, Type.GetTypeCode(typeof(int))); 
     break; 
    default: 
     throw new ArgumentOutOfRangeException("variable"); 
    } 
} 

public T Get<T>(GetEnum member) { 
    switch (member) { 
     case GetEnum.Calculated: return (T)Convert.ChangeType(Calculated, Type.GetTypeCode(typeof(T))); 
     case GetEnum.Result: return (T)Convert.ChangeType(Result, Type.GetTypeCode(typeof(T))); 
     default: throw new ArgumentOutOfRangeException("member"); 
    } 
} 

public void Run(RunEnum member) { 
    switch (member) { 
     case RunEnum.Add: Add(); break; 
     case RunEnum.Subtract: Subtract(); break; 
     case RunEnum.Reset: Reset(); break; 
     default: throw new ArgumentOutOfRangeException("member"); 
    } 
} 

private void Add() { 
    Result = Val1 + Val2; 
    Calculated = true; 
} 

private void Subtract() { 
    Result = Val1 - Val2; 
    Calculated = true; 
} 

private void Reset() { 
    Result = 0; 
    Calculated = false; 
} 
} 

回答

1

我会使用普通的接口来代替。这更简洁,更简单。

而把真正落实界面和UI看到接口之间的代理。该代理可以在运行时动态生成,并可以进行日志记录。我确定有一些现有的库可以为您生成代理,但是要感谢Expression,您自己也不难编写代理。

正常界面我的意思是类似以下内容:

interface MyInterface 
{ 
    double Value1{get;set;} 
    void Add(); 
    void Sub(); 
} 

就像你会写任何接口。然后在普通课堂上实施。我自己并没有使用任何代理生成器,但我确信有几个模拟和AoP框架支持这一点。 dynamic proxy C#的快速谷歌变成http://joe.truemesh.com/blog//000181.html,它声称NMock支持这一点。

另一种方法是使用基于IL重写的AOP框架,如PostSharp。您将它指向您的程序集(作为构建过程的一部分),并自动将日志记录调用添加到其中。

+0

你可以扩展你的意思是'正常接口'。我正在寻找一种方法来编写一次记录代码。任何未来的组件都可以实现这一点,并保证不需要编写任何代码即可支持日志记录。另外,你能否给我提供一个描述你所引用的代理和表达式的链接。一些Google的快速搜索发现这些术语相当宽泛。 – c31983

+0

通过正常的接口我的意思是写它们的自然方式。简单的属性和方法。 – CodesInChaos

0

另一种解决方案尚未:只需添加基类的虚方法,并实现它,用具体的实施将覆盖任何“组件”和调用基类的方法,就是你实际写记录的东西。

那么你需要知道组件的“ID”。这也可能是虚拟财产,每个具体的类都分配了其独特的“ID”。

希望这会有所帮助。