2012-10-29 25 views
6
chương trình

mẫu dưới đây:Bạn có thể giải thích hành vi generics này và nếu tôi có cách giải quyết khác không?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace GenericsTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IRetrievable<int, User> repo = new FakeRepository(); 

      Console.WriteLine(repo.Retrieve(35)); 
     } 
    } 

    class User 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 

    class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
    { 
     // why do I have to implement this here, instead of letting the 
     // TKey generics implementation in the baseclass handle it? 
     //public User Retrieve(int input) 
     //{ 
     // throw new NotImplementedException(); 
     //} 
    } 

    class BaseRepository<TPoco> where TPoco : class,new() 
    { 
     public virtual TPoco Create() 
     { 
      return new TPoco(); 
     } 

     public virtual bool Delete(TPoco item) 
     { 
      return true; 
     } 

     public virtual TPoco Retrieve<TKey>(TKey input) 
     { 
      return null; 
     } 
    } 

    interface ICreatable<TPoco> { TPoco Create(); } 
    interface IDeletable<TPoco> { bool Delete(TPoco item); } 
    interface IRetrievable<TKey, TPoco> { TPoco Retrieve(TKey input); } 
} 

chương trình mẫu này đại diện cho giao diện chương trình thực tế của tôi sử dụng, và chứng minh những vấn đề tôi đang gặp (nhận xét ra trong FakeRepository). Tôi muốn gọi phương thức này được xử lý chung bởi lớp cơ sở (trong ví dụ thực tế của tôi có thể xử lý 95% các trường hợp được cho nó), cho phép ghi đè trong các lớp con bằng cách chỉ rõ kiểu TKey một cách rõ ràng. Nó dường như không có vấn đề gì ràng buộc tham số tôi sử dụng cho IRetrievable, tôi không bao giờ có thể nhận được các cuộc gọi phương pháp để rơi qua lớp cơ sở.

Ngoài ra, nếu có ai có thể nhìn thấy một cách thay thế để thực hiện loại hành vi này và nhận được kết quả cuối cùng tôi đang tìm kiếm, tôi sẽ rất quan tâm để xem nó.

Suy nghĩ?

Trả lời

3

Đó là mã không biên dịch vì lý do tương tự ví dụ đơn giản này không biên dịch:

public interface IBar 
{ 
    void Foo(int i); 
} 

public class Bar : IBar 
{ 
    public void Foo<T>(T i) 
    { 
    } 
} 

Các phương pháp đơn giản không có chữ ký giống nhau. Có, bạn có thể gọi someBar.Foo(5) và nó sẽ giải quyết T thành int, nhưng thực tế vẫn là Foo trong Bar vẫn không có chữ ký giống như phương thức thực sự lấy tham số int.

Bạn có thể chứng minh điều này bằng cách có cả phương pháp không chung chung và chung chung trong loại; điều này không gây ra một lỗi liên quan đến sự mơ hồ:

public class Bar : IBar 
{ 
    public void Foo(int i) 
    { 

    } 
    public void Foo<T>(T i) 
    { 
    } 
} 

Đối với thực giải quyết vấn đề của bạn, bạn có thể làm điều này:

class FakeRepository : BaseRepository<User>, ICreatable<User>, IDeletable<User>, IRetrievable<int, User> 
{ 
    public User Retrieve(int input) 
    { 
     return Retrieve<int>(input); 
    } 
} 

Điều này có nghĩa rằng FakeRespository có cả chung chung và không chung chung phiên bản Retrieve, nhưng cuối cùng tất cả các cuộc gọi vẫn được chuyển hướng đến phiên bản chung.

1

Trình biên dịch không biết TKey là gì trong BaseRepository và không có cách nào liên quan đến số này IRetreivable (lưu ý rằng các phương thức chung không có chữ ký giống với các phương thức không chung chung).

Tôi nghĩ rằng bạn muốn một cái gì đó hơn dọc theo những dòng này, với lớp cơ sở làm kế thừa giao diện, và cũng để xác định TKey:

class FakeRepository : BaseRepository<int, User> 
{ 
} 

class BaseRepository<TKey, TPoco> : ICreatable<TPoco>, IDeletable<TPoco>, IRetrievable<TKey, TPoco> where TPoco : class,new() 
{ 
    public virtual TPoco Create() 
    { 
     return new TPoco(); 
    } 

    public virtual bool Delete(TPoco item) 
    { 
     return true; 
    } 

    public virtual TPoco Retrieve<TKey>(TKey input) 
    { 
     return null; 
    } 
} 
+0

Một điều cần thêm, và tiếc là tôi không đưa nó vào ví dụ ban đầu, là FakeRepository của tôi có thể có một số giao diện IRetrievable được xác định, tất cả đều có cùng TPoco, nhưng TKey khác nhau. –