2013-09-03 30 views
8

tôi biết làm thế nào để buộc một tham số kiểu là một kiểu phụ loại khác:Constrain loại tham số cho một loại cơ sở

public interface IMapping<T2> 
{ 
    public void Serialize<T3>(T3 obj) 
     where T3 : T2; 
} 
... 

var mapping = MapManager.Find<Truck>(); 
mapping.Serialize(new TonkaTruck()); 

Có cách nào để buộc một tham số kiểu để trở thành một siêu kiểu loại khác?

public interface IMapping<T2> 
{ 
    public void IncludeMappingOf<T1>() 
     where T2 : T1; // <== doesn't work 
} 
... 

var mapping = MapManager.Find<Truck>(); 

// Truck inherits Vehicle  
// Would like compiler safety here: 
mapping.IncludeMappingOf<Vehicle>(); 

mapping.Serialize(new TonkaTruck()); 

Hiện nay, tôi đang gặp để so sánh T1 và T2 khi chạy bằng IsSubclassOf bên IncludeMappingOf. Một giải pháp biên dịch an toàn sẽ thích hợp hơn. Bất kỳ ý tưởng?

EDIT: Thay đổi ví dụ thành thiết kế ít mùi hơn.

LƯU Ý: Câu hỏi được liên kết tương tự nhau nhưng không có câu trả lời phù hợp. Hy vọng rằng câu hỏi này sẽ làm sáng tỏ điều đó.

EDIT # 2:

đơn giản ví dụ:

public class Holder<T2> 
{ 
    public T2 Data { get; set; } 

    public void AddDataTo<T1>(ICollection<T1> coll) 
     //where T2 : T1 // <== doesn't work 
    { 
     coll.Add(Data); // error 
    } 
} 

... 
var holder = new Holder<Truck> { Data = new TonkaTruck() }; 
var list = new List<Vehicle>(); 
holder.AddDataTo(list); 

Compiler: Loại Đối số 'T2' là không thể chuyển nhượng để tham số type 'T1'. Vâng tôi biết rằng, tôi đang cố gắng để có được trình biên dịch để chỉ cho phép các trường hợp T2 IS gán cho kiểu tham số T1!

+3

Khá thú vị một câu hỏi, tuy nhiên tôi không thể lắc cảm giác rằng có thể có một vấn đề thiết kế ở đây, tại sao không 'TruckMapping' kế thừa' VehiculeMapping' thay vì 'IMapping'? Tôi có nghĩa là nó âm thanh như bản đồ xe tải là một phiên bản chuyên biệt của bản đồ xe tổng quát hơn hoặc tôi thiếu cái gì? –

+0

Có liên quan mạnh mẽ (trùng lặp): [Có thể hạn chế một tham số kiểu phương thức chung của C# như “có thể gán từ” tham số kiểu của lớp chứa không?] (Http://stackoverflow.com/questions/11255558/is-it-possible -to-constrain-ac-sharp-generic-method-kiểu-tham số-as-assignab) –

+0

@SimonRapilly: Có lẽ đúng. Đây là một ví dụ giả tạo để giúp minh họa vấn đề. Tôi đã thay đổi ví dụ lên một chút. – CSJ

Trả lời

1

Bạn có thể sử dụng các phương pháp mở rộng để đến gần với những gì bạn muốn.Sử dụng ví dụ người nắm giữ của bạn nó sẽ là:

public class Holder<T2> 
{ 
    public T2 Data { get; set; } 
} 

public static class HolderExtensions 
{ 
    public static void AddDataTo<T2, T1>(this Holder<T2> holder, ICollection<T1> coll) 
     where T2 : T1 
    { 
     coll.Add(holder.Data); 
    } 
} 

Đó sau đó cho phép ví dụ của bạn gọi mã để biên dịch mà không có lỗi:

var holder = new Holder<Truck> { Data = new TonkaTruck() }; 
var list = new List<Vehicle>(); 
holder.AddDataTo(list); 

Ví dụ lập bản đồ là phức tạp bởi thực tế là nó là một giao diện. Có thể cần thêm phương thức triển khai vào giao diện nếu không có cách nào để triển khai phương thức mở rộng từ giao diện hiện có. Điều đó có nghĩa là bạn vẫn sẽ cần một kiểm tra thời gian chạy, nhưng người gọi có thể nhận được cú pháp tốt và kiểm tra thời gian biên dịch. Đó sẽ là một cái gì đó như:

public interface IMapping<T2> 
{ 
    void IncludeMappingOf(Type type); 
} 

public static class MappingExtensions 
{ 
    public static void IncludeMappingOf<T2, T1>(this IMapping<T2> mapping) 
     where T2 : T1 
    { 
     mapping.IncludeMappingOf(typeof(T1)); 
    } 
} 

Đáng tiếc thay, IncludeMappingOf không có một tham số kiểu T1 nên các thông số loại không thể được suy ra. Bạn buộc phải ghi rõ cả hai loại khi gọi nó:

var mapping = MapManager.Find<Truck>(); 
mapping.IncludeMappingOf<Truck, Vehicle>(); 
mapping.Serialize(new TonkaTruck()); 

Đó thường có thể được giải quyết bằng cách thay đổi các API để bao gồm một tham số (ví dụ: truckMapping.IncludeMappingOf(vehicleMapping)), thay đổi phương pháp/lớp tham số là trên hoặc trong các API thông thạo tạo chuỗi (ví dụ: mapping.Of<Vehicle>().Include()).

+0

Điều này là rất thông minh, nếu không phải là một chút không thích hợp (logic cho lớp của tôi bây giờ là lây lan qua hai lớp) - nhưng nó đạt được mục tiêu! – CSJ

4

Declare cả hai loại generic và hạn chế chung ở lớp (giao diện) mức:

public interface IMapping<T1, T2> where T2 : T1 
{ 
    void IncludeMapping(IMapping<T1, T2> otherMapping); 
} 
+1

Điều này có nghĩa là bất kỳ thể hiện nào của lớp phải luôn sử dụng 'T3' ​​như được khai báo, trong khi mục đích ban đầu bạn có thể khai báo/khởi tạo đối tượng, sau đó chuyển bất kỳ số kiểu nào khác vào phương thức' Serialize'. 'là một kiểu có nguồn gốc. Hơn nữa, câu hỏi đã được yêu cầu để hạn chế 'T2' như là một loại có nguồn gốc của' T3', không phải là cách khác xung quanh. EDIT: Ahh, bạn chỉ cần chỉnh sửa câu trả lời của bạn. Bỏ qua phần thứ hai của bình luận của tôi. –

+1

Bạn có thể cần phải cập nhật chỉnh sửa của mình. Bạn có lẽ không nên redeclare '' và các ràng buộc của nó trong phương thức giao diện; Tôi tin rằng đây sẽ là những loại mới được khai báo không có mối quan hệ với '' là một phần của khai báo giao diện. –

+0

@ChrisSinclair bạn nói đúng; Tôi nhận ra rằng và cập nhật câu trả lời của tôi – GolfWolf

5

Trong khi câu trả lời w0lf của đưa ra một giải pháp trực tiếp, tôi muốn đưa ra một số lời giải thích nền.

Khi bạn viết một cái gì đó giống như

class C<A> where A : B 

hoặc

void F<A>() where A : B 

những hạn chế của hình thức A : B phải có A là một trong những tham số kiểu chung chung trên lớp, giao diện, phương pháp vv được tuyên bố.

Lỗi bạn đang gặp phải là không vì bạn đã đặt thông số kiểu chung của khai báo hiện tại ở bên phải dấu hai chấm (đó là hợp pháp) - đó là vì bạn đã đặt thông số loại chung của khai báo bên ngoài (không phải khai báo hiện hành) ở phía bên trái của dấu hai chấm.

Nếu bạn muốn hình thành một hạn chế A : B trên một số tờ khai, A phải được giới thiệu trên tờ khai đó và phạm vi A phải nhỏ hơn hoặc bằng với phạm vi B. Lý do này là một hạn chế ngôn ngữ thực dụng là, đối với bất kỳ tham số kiểu chung nào T, nó tách biệt bất kỳ lý do nào về các ràng buộc về loại T thành khai báo đơn lẻ nơi T đang được giới thiệu.

+0

Chắc chắn, tôi hiểu.Nhưng bạn có thể thấy những gì tôi đang cố gắng đạt được. – CSJ

+0

@CSJ Tôi thấy những gì bạn đang cố gắng đạt được, nó rất rõ ràng. Điều tôi giải thích là có một hạn chế ngôn ngữ ngăn cản bạn làm điều đó. Những hạn chế về ngôn ngữ này về cơ bản làm cho biểu đồ ràng buộc kiểu generic trở thành một cây làm cho lý luận về nó dễ dàng hơn, với chi phí của một số biểu cảm. Bạn có thể sử dụng gợi ý của w0lf như một giải pháp cho vấn đề này. –

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