使用泛型实现简化的对象接口

时间:2011-07-11 17:51:53

标签: c# generics interface

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

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

代码编译并运行,但我知道我没有很好地实现它。通过在简单对象强制转换上使用Convert.ChangeType,我可能不会在Get或Set函数中保存任何费用。我也在摧毁仿制药应该提供的类型安全性。

虽然欢迎对此任何部分提出建议,但最佳答案可能会被授予解决方案,该解决方案显示了我应该如何使用泛型来正确实现这一点。以下是我正在使用的代码来说明目前的概念:

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;
}
}

2 个答案:

答案 0 :(得分: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。您将它指向程序集(作为构建过程的一部分),并自动将日志记录调用添加到其中。

答案 1 :(得分:0)

另一种解决方案:只需添加带有虚拟方法的基类和任何实现它的“组件”,用具体实现覆盖它,并调用基类方法实际编写日志记录的东西。

你需要知道组件的“ID”。这也可能是虚拟财产,每个具体的类都会分配其唯一的“ID”。

希望这有帮助。