2016-03-31 71 views
1

我有一個閱讀模型爲IQueryable<CustomType>,我在我的Web應用程序中使用它。很多時候我需要從這個閱讀模型中提取不同的視圖模型。如何在c#中基於通用返回類型模擬方法重載

我用它編寫擴展方法,如:

public static ViewModelA AsViewModelA(this IQueryable<CustomType> query) 
{ 
    var vm = view 
       .Select(x => new ViewModelA 
       { 
        Something = x.Something 
       }).FirstOrDefault(); 

    return vm; 
} 

public static ViewModelB AsViewModelB(this IQueryable<CustomType> query) 
{ 
    var vm = view 
       .Select(x => new ViewModelB 
       { 
        SomethingElse = x.SomethingElse 
       }).FirstOrDefault(); 

    return vm; 
} 

該做的工作,但我不喜歡與方法名產生的混亂;一個更通用的方法,這樣的事情將是可取的:

query.AsViewModel<ViewModelA>() 

我知道,返回類型不作爲方法的簽名(所以沒有超載適用),我知道泛型類型是不足以使過載。 我會是一個機制,只是模擬基於泛型類型的重載。這種機制應該避免使用if/then/else級聯的主要方法。有一種方法?也許動態?

+2

「TypeA」是否爲'ViewModelA'?每種情況下的實現是什麼樣的? –

+0

@JonSkeet更正了執行 –

回答

0

嗯,是的,你可以使用dynamic

private static ViewModelA AsViewModelInternal(this IQueryable<CustomType> query, 
               ViewModelA dummy) { ... } 

private static ViewModelB AsViewModelInternal(this IQueryable<CustomType> query, 
               ViewModelB dummy) { ... } 

public static T AsViewModel<T>(this IQueryable<CustomType> query) 
{ 
    return (T)query.AsViewModelInternal(default(T)); 
} 

確保處理不存在超載,當然,:)最簡單的方法是添加一個重載需要object作爲最後一個參數,所以你基本上有一個「後備超負荷」。

但是,我不會推薦。泛型最大的好處之一是你可以獲得很好的編譯時間檢查。這個泛型方法假裝接受所有可能的T,但實際上並不是。這相當於取代object而不是ViewModelA/ViewModelB

它不象有一個世界上的差異

之間
query.AsViewModelB() 

query.AsViewModel<ViewModelB>() 

我只用選擇,如果你經常發現自己有打電話AsViewModel時使用泛型類型參數,即當你不知道具體的類型時,

1

一種選擇是從該類型到CustomType到該類型的轉換。所以它看起來東西這樣的:

private static readonly Dictionary<Type, Expression> Mappings = 
    new Dictionary<Type, Expression> 
    { 
     { typeof(ViewModelA), 
      Helper<ViewModelA>(x => new ViewModelA { Something = x.Something }) }, 
     { typeof(ViewModelB), 
      Helper<ViewModelB>(x => new ViewModelB { SomethingElse = x.SomethingElse }) }, 
     ... 
    } 

// This method just helps avoid casting all over the place. 
// In C# 6 you could use an expression-bodied member - or add a 
private static Expression<Func<CustomType, T>> Helper<T> 
    (Expression<Func<CustomType, T>> expression) 
{ 
    return expression; 
} 

public static T AsViewModel<T>(this IQueryable<CustomType> query) 
{ 
    Expression rawMapping; 
    if (!Mappings.TryGetValue(typeof(T), out rawMapping)) 
    { 
     throw new InvalidOperationException("Or another exception..."); 
    } 
    // This will always be valid if we've set up the dictionary properly 
    var mapping = (Expression<Func<CustomType, T>>) rawMapping; 
    return view.Select(mapping).FirstOrDefault(); 
} 

您可以字典建設有點吸塵器多一點的前期代碼。

+0

我應該避免使用這些方法嗎?只需更改方法名稱? –

+0

@ marianoc84:那取決於你。如果你只有少數這些,那麼有多種方法是合理的。如果你有很多視圖模型,那麼這裏的字典方法非常好 - 當然,它不會給你編譯時檢查你的類型參數。 –

相關問題