2015-10-12 24 views
8

考慮到如下界面:開放通用的限制

public interface IQuerySpec<M> { } 

我很想做的擴展方法是這樣的:

public static OrderedSortation<T> OrderBy<T, TKey>(
    this T query, 
    Expression<Func<T, TKey>> sort) 
where T : IQuerySpec<?> { 
    //business as usual 
} 

我只是想確保類型TIQuerySpec<M>一些變化。然後我可以調用擴展方法如下:

public class Foo : IQuerySpec<int> { 
    public int SizeOfSailBoat {get; set;} 
} 

IQuerySpec<Foo> foo = new Foo {SizeOfSailBoat = 10}. 
var result = foo.OrderBy(f => f.SizeOfSailBoat); 

的UDT Foo在上面的例子中被指定,但我不在乎是做什麼用泛型類型參數。

有沒有辦法做到這一點?

我試過如下:

public static OrderedSortation<T> OrderBy<T, M, TKey>(
    this T query, 
    Expression<Func<T, TKey>> sort) 
where T : IQuerySpec<M> { 
    //business as usual 
} 

上述工作,但要求通用參數,以便明確指出調用「排序依據」。我不希望被要求明確說明通用參數。

我也試過這樣:

public interface IQuerySpec {} 
public interface IQuerySpec<M> : IQuerySpec {} 

通過這些接口,那麼我可以這樣做:

public static OrderedSortation<T> OrderBy<T, TKey>(
    this T query, 
    Expression<Func<T, TKey>> sort) 
where T : IQuerySpec { 
    //business as usual 
} 

這幾乎是不夠好,但我想隱藏的非通用IQuerySpec所以它在我的類庫之外是不可見的。如果我可以用這種方式限定非通用接口,我很樂意:

internal interface IQuerySpec {} 

不幸的是,編譯器不會讓我這樣做。

我猜我想要什麼是不可能的,但爲了以防萬一。

+0

你能舉一個例子說明你想要的用法語法是什麼樣子的嗎? –

+0

@Mike:我添加了一個調用示例。 –

回答

0

問題是,編譯器無法從M中隱式地推斷出M或T中的M的類型。

所以需要修正一個它們,這裏我一定的T至IQuerySpec<M>

和延伸方法的簽名變得

public static OrderedSortation<IQuerySpec<M>> OrderBy<M, TKey>(
    this IQuerySpec<M> query, 
    Expression<Func<IQuerySpec<M>, TKey>> sort) 

    { 
     //business as usual 
    } 

爲例

class IntQSpec : IQuerySpec<int> 
    { 
     //your implementation 
    } 

,這裏是調用示例

var iQS = new IntQSpec(); 
//do whatever you want with iQS 
var ord = iQS.OrderBy(ii=>ii.ToString()); 
//here I called OrderBy without the need to explicitly specifying the Generic Arguments 

這裏是你的代碼上的Visual Studio 2013- 2015年試驗中,沒有錯誤的突出 注意,我訪問的具體類型IntQSpec enter image description here

的Z字段我希望這將有助於。

+0

我修改了我的問題,以澄清表達式樹必須能夠訪問具體IQuerySpec 的成員。在我的例子中,我訪問了「SizeOfSailBoat」,它在具體的'Foo'類中可用,但在IQuerySpec 接口上不可用。所以你在這裏的例子是行不通的。 –

+0

好的,如果你使用visual studio 2010和更早的版本,那麼編譯器就無法做你想隱式的工作,但是在visual studio 2013-2015上工作時沒有指定泛型參數 – Aladdin

+0

我使用的是VS 2015.在你提供的例子中,你傳遞'M'到表達式樹中。表達式樹必須能夠訪問'T'而不是'M'。 –

0

這在我看來,要麼根本不需要IQuerySpec<M>和應該只是IQuerySpecTKey應根據我所看到的在這裏永遠是M。我懷疑取代,從而消除IQuerySpec<M>IQuerySpec是你真正想要基於你的願望M打開。這是一個證明。請看看它是否適合你所要完成什麼,或者如果在途中對最終的解決方案中的步驟之一是接近:

假設IQuerySpec<M>其實是在需要和M應該始終等於TKey,下面的編譯和會您的實現可能工作:

假設TKeyM

public interface IQuerySpec<M> { } 
public class OrderedSortation<T> {} 
public static class IQuerySpecExtensions 
{ 
    public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec<TKey> 
    { 
     throw new NotImplementedException(); // business as usual 
    } 
} 
public class Foo : IQuerySpec<int> { public int SizeOfSailBoat {get; set;} } 

用法:

public class Demo 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo {SizeOfSailBoat = 10}; 
     var result = foo.OrderBy(f => f.SizeOfSailBoat); 
    } 
} 

假設多個TKey選項的需要:

如果您需要支持其他類型的其他屬性(開放類更多的查詢的可能性),那麼你的類可能是這樣的,例如:

public interface IQuerySpec<M> { } 
public class OrderedSortation<T> {} 
public static class IQuerySpecExtensions 
{ 
    public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec<TKey> 
    { 
     throw new NotImplementedException(); // business as usual 
    } 
} 
public class Foo : IQuerySpec<int>, IQuerySpec<string> 
{ 
    public int SizeOfSailBoat {get; set;} 
    public string NameOfSailBoat {get; set;} 
} 

用法:

public class Demo 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo {SizeOfSailBoat = 10}; 
     var result = foo.OrderBy(f => f.SizeOfSailBoat); 
     result = foo.OrderBy(f => f.NameOfSailBoat); 
    } 
} 

減少IQuerySpec<M>IQuerySpec

在這種情況下,你可以只簡化爲僅具有IQuerySpec這樣的:

public interface IQuerySpec { } 
public class OrderedSortation<T> {} 
public static class IQuerySpecExtensions 
{ 
    public static OrderedSortation<T> OrderBy<T, TKey>(this T query, System.Linq.Expressions.Expression<Func<T, TKey>> sort) where T : IQuerySpec 
    { 
     throw new NotImplementedException(); // business as usual 
    } 
} 
public class Foo : IQuerySpec 
{ 
    public int SizeOfSailBoat {get; set;} 
    public string NameOfSailBoat {get; set;} 
} 

用法:

public class Demo 
{ 
    public static void Main() 
    { 
     Foo foo = new Foo {SizeOfSailBoat = 10}; 
     var result = foo.OrderBy(f => f.SizeOfSailBoat); 
     result = foo.OrderBy(f => f.NameOfSailBoat); 
    } 
} 

上述所有作品禁止說的在IQuerySpec中沒有定義實際的方法或屬性簽名,它們參考M