2016-11-07 66 views
1

我想寫一些能夠採取各種行爲類,並將它們鏈接到查詢和命令鏈。我採取的一種方法是在下面,但我遇到了將派生類型轉換爲基類型的問題。我不得不處理泛型參數,而且我不確定這種方法是不可能的,或者我需要定義一些隱式或顯式轉換運算符,或者完全是其他的。鑄造到少衍生類型和處理泛型

這是一組基本類型。首先是最基本的接口:

public interface IInvoker 
{ 
    void Invoke(); 
} 

這個抽象類增加了有一個「主題」,它是通過其成員之一是否命令或查詢的東西的能力。它會延遲執行Invoke方法:

public abstract class AbstractInvoker<TSubject> : IInvoker 
{ 
    protected TSubject Subject; 

    public void SetSubject(TSubject subject) 
    { 
     Subject = subject; 
    } 

    public abstract void Invoke(); 
} 

這下一個抽象類是由任何具體的查詢類實現(而不是一個命令,該命令將不具有TResult類型)的類型。它設置了通過後繼鏈接查詢的能力。

public abstract class AbstractQueryInvoker<TSubject, TResult> : AbstractInvoker<TSubject> 
{ 
    protected AbstractInvoker<TResult> Successor; 

    public void SetSuccessor(AbstractInvoker<TResult> successor) 
    { 
     Successor = successor; 
    } 

    public override void Invoke() 
    { 
     var result = DoQuery(); 

     Successor.SetSubject(result); 
     Successor.Invoke(); 
    } 

    protected abstract TResult DoQuery(); 
} 

實際查詢邏輯通過DoQuery()方法在具體類中實現。

我把它這樣,所以我可以鏈查詢起來是這樣的:

private List<IInvoker> _invokers; 

// Build the list of various concrete classes 

for (int i = 0; i < _invokers.Count - 1; i++) 
{ 
    ((AbstractQueryInvoker<dynamic, dynamic>)_invokers[i]).SetSuccessor(
                     (AbstractInvoker<dynamic>) 
                     _invokers[i + 1]); 
} 

我的目標是讓每個調用,除了最後一個,有其接班人拴了這裏,所以一切我需要做的就是在第一個元素上調用Invoke()。然而,for循環中的第一次投射不起作用(第二次也許不會,我猜測)。錯誤信息看起來是這樣的:

我希望有一些方法來解決這個問題,而無需實現每個具體祈求什麼特別的事。我最終可能會有幾十個這樣的具體類,每個類都使用泛型類型參數的不同類型。那麼,有沒有辦法來解決這個問題?

+1

在你的榜樣的名稱不一致。例如'IActionInvoker'沒有顯示在任何地方。請發佈可編譯的真實代碼。 –

+0

@JesseGood - 修正。 – bubbleking

回答

0

每個調用只投給dynamic

// Build the list of various concrete classes 
for (int i = 0; i < _invokers.Count - 1; i++) 
{ 
    ((dynamic)_invokers[i]).SetSuccessor((dynamic)_invokers[i + 1]); 
} 

爲什麼你的原始代碼不起作用: 雖然AbstractQueryInvoker<dynamic, dynamic>使用dynamic關鍵字,它也不是一個動態的類型只dynamic本身是動態的, 。在運行時,dynamic類型參數被替換爲object,因此轉換失敗。

+0

有趣。這工作。你是否說如果我使用了對象而不是動態的,它也會起作用?無論如何,謝謝。 – bubbleking

+1

不,我只是指出運行時異常提到''AbstractQueryInvoker'2 [System.Object,System.Object]'',因爲'dynamic'被'object'取代。' –

+0

我第一次誤解了你。現在我再次閱讀,很明顯,使用對象而不是動態不會改變轉換爲對象失敗的事實! – bubbleking

1

如果我明白你想要做什麼,我認爲你已經讓你的代碼有點複雜並且可能很脆弱。

告訴我,如果這樣的事情是對你更好:

IInvoker<string> invoker = 
    5 
     .CreateBehaviour() 
     .AddBehaviour(n => n * 2) 
     .AddBehaviour(n => n + 1) 
     .AddBehaviour(n => n.ToString()) 
     .AddBehaviour(n => n + "!"); 

Console.WriteLine(invoker.Invoke()); 

這運行的每個步驟之後輸出"11!"

做它的代碼是這樣的:

public static class BehaviorsEx 
{ 
    private class Subject<TSubject> : IInvoker<TSubject, TSubject> 
    { 
     private TSubject _subject; 

     public Subject(TSubject subject) 
     { 
      _subject = subject; 
     } 

     public TSubject Invoke() { return _subject; } 
    } 

    private class Invoker<TSubject, TResult> : IInvoker<TSubject, TResult> 
    { 
     private IInvoker<TSubject> _inner; 
     private Func<TSubject, TResult> _behaviour; 

     public Invoker(IInvoker<TSubject> inner, Func<TSubject, TResult> behaviour) 
     { 
      _inner = inner; 
      _behaviour = behaviour; 
     } 

     public TResult Invoke() 
     { 
      var x = _inner.Invoke(); 
      return _behaviour(x); 
     } 
    } 

    public static IInvoker<TSubject> CreateBehaviour<TSubject>(this TSubject @this) 
    { 
     return new Subject<TSubject>(@this); 
    } 

    public static IInvoker<TResult> AddBehaviour<TSubject, TResult>(this IInvoker<TSubject> @this, Func<TSubject, TResult> behaviour) 
    { 
     return new Invoker<TSubject, TResult>(@this, behaviour); 
    } 
} 

public interface IInvoker<TResult> 
{ 
    TResult Invoke(); 
} 

public interface IInvoker<TSubject, TResult> : IInvoker<TResult> 
{ 
} 
+0

有趣。今天我會試着去玩這個,看看它是如何工作的,我會盡快回復你。 – bubbleking

+0

我認爲這可能不適合我的情況,但我會看看是否有類似的變化,特別是Func和Action。我所做的實質上是執行一個宏。宏所需每個步驟的定義都將存儲在數據庫中。每個宏都有一個或多個查詢,後跟一個命令。每個查詢都有一個主題,結果和一個後繼。後繼者是另一個查詢或最終命令。最後的命令對查詢字符串的結果進行無效操作。實際上,該過程如下所示:(請參見下一條評論) – bubbleking

+0

對於B類型對象,查詢集合A將結果傳遞給下一個查詢... 查詢集合B用於C類型對象,將它傳遞給.. 。 查詢C爲D,將它傳遞給... 在D的每個元素上運行命令。 我忘記提及一個命令只有一個主題。它沒有結果或者繼任者。但是,爲了執行一系列查詢(使用不同的類型參數),然後執行一條命令,我需要在它們之間建立一個通用接口,這就是IInvoker 的地方。通過這種方式,我可以從數據庫獲取指令記錄,組裝它們以便調用鏈。 – bubbleking