2015-10-12 22 views
8

Với giao diện sau:mở Generic Hạn chế

public interface IQuerySpec<M> { } 

Tôi rất thích để thực hiện một phương pháp khuyến nông như thế này:

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

tôi chỉ đơn giản muốn chắc chắn rằng loại T là một số biến thể của IQuerySpec<M> . sau đó tôi có thể gọi phương thức mở rộng như sau:

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

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

Các UDT Foo đã được chỉ định trong ví dụ trên, nhưng tôi không quan tâm những gì tham số kiểu generic được sử dụng.

Có cách nào để thực hiện việc này không?

tôi thử như sau:

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

Các công trình trên, nhưng đòi hỏi rằng các tham số chung được quy định rõ ràng để gọi "OrderBy". Tôi không muốn được yêu cầu nêu rõ các thông số chung.

Tôi cũng đã cố gắng này:

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

Với các giao diện sau đó tôi có thể làm điều này:

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

này là gần như đủ tốt, ngoại trừ việc tôi muốn ẩn IQuerySpec không chung chung quá rằng nó không thể nhìn thấy bên ngoài thư viện lớp học của tôi. Tôi rất thích nếu tôi có thể có phạm vi giao diện không chung chung theo cách này:

internal interface IQuerySpec {} 

Thật không may trình biên dịch sẽ không cho phép tôi làm điều đó.

Tôi đoán những gì tôi muốn là không thể, nhưng yêu cầu chỉ trong trường hợp.

+0

Bạn có thể đưa ra ví dụ về những gì bạn muốn cú pháp của việc sử dụng giống như không? –

+0

@Mike: Tôi đã thêm ví dụ gọi. –

Trả lời

0

vấn đề là trình biên dịch không thể suy ra loại M từ T hoặc T từ M ngầm.

vì vậy bạn cần phải sửa chữa một họ, ở đây tôi cố định T để IQuerySpec<M>

và chữ ký của phương pháp mở rộng trở thành

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

    { 
     //business as usual 
    } 

làm ví dụ

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

và đây là ví dụ về yêu cầu

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 

đây là sự thử thách của mã của bạn trên visual studio 2013-2015, không có lỗi mà nhấn mạnh lưu ý rằng tôi truy cập vào lĩnh vực Z của kiểu dữ liệu cụ IntQSpec enter image description here

Tôi hy vọng nó sẽ giúp.

+0

Tôi đã sửa đổi câu hỏi của mình để làm rõ rằng cây biểu thức phải có khả năng truy cập các thành viên của IQuerySpec cụ thể . Trong ví dụ của tôi, tôi truy cập "SizeOfSailBoat", có sẵn trên lớp 'Foo' cụ thể, nhưng không có sẵn trên giao diện IQuerySpec . Vì vậy, ví dụ bạn có ở đây sẽ không hoạt động. –

+0

ok, Nếu bạn sử dụng studio hình ảnh 2010 và trước đó thì trình biên dịch không thực hiện những gì bạn muốn, nhưng trên studio trực quan 2013-2015 không xác định đối số chung – Aladdin

+0

Tôi đang sử dụng VS 2015. Trong ví dụ bạn đã cung cấp , bạn đang chuyển 'M' vào cây biểu thức. Cây biểu thức phải có quyền truy cập vào 'T' thay vì' M'. –

0

Dường như với tôi rằng IQuerySpec<M> không cần thiết và chỉ nên là IQuerySpec hoặc TKey phải luôn là M dựa trên những gì tôi thấy ở đây. Tôi nghi ngờ rằng thay thế và do đó loại bỏ IQuerySpec<M> với IQuerySpec là những gì bạn thực sự muốn dựa trên mong muốn của bạn rằng Mmở. Đây là một bằng chứng. Xin vui lòng xem nếu nó phù hợp với những gì bạn đang cố gắng để thực hiện hoặc nếu một trong những bước trên đường đến giải pháp cuối cùng là gần gũi hơn:

Giả sử rằng IQuerySpec<M> được trong thực tế cần thiết và M nên luôn bằng TKey, các biên dịch sau đây và sẽ có khả năng làm việc với thực hiện của bạn:

Giả sử 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;} } 

Cách sử dụng:

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

Giả sử nhu cầu nhiều TKey lựa chọn:

Nếu bạn cần hỗ trợ các tài sản khác của các loại khác (mở lớp cho khả năng truy vấn nhiều hơn), sau đó lớp học của bạn có thể trông như thế này ví dụ :

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

Cách sử dụng:

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

Giảm IQuerySpec<M>-IQuerySpec:

Trong trường hợp này bạn chỉ có thể đơn giản hóa chỉ có IQuerySpec như thế này:

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

Cách sử dụng:

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

Tất cả các công trình trên chặn mà không có ký hiệu phương thức hoặc thuộc tính thực tế được xác định trên IQuerySpec tham chiếu đến M.

Các vấn đề liên quan