2011-07-11 103 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」。

希望這會有所幫助。