2009-04-27 40 views
21

tôi có mã C# này:trừu tượng thực hiện giao diện rõ ràng trong C#

abstract class MyList : IEnumerable<T> 
{ 
    public abstract IEnumerator<T> GetEnumerator(); 

    //abstract IEnumerator IEnumerable.GetEnumerator(); 
} 

Như là, tôi nhận được:

'Loại' không thực hiện thành viên giao diện 'System.Collections.IEnumerable.GetEnumerator() '.

loại bỏ những nhận xét và tôi nhận được:

Các modifier 'trừu tượng' không hợp lệ cho mặt hàng này

Làm thế nào để làm cho một thực hiện trừu tượng rõ ràng

+0

này là một thiếu sót của trình biên dịch C# IMHO. Có rất nhiều trường hợp sử dụng, nơi bạn sẽ phải thêm một giả thực hiện "chỉ vì". Ngoài ra, nếu bạn đã chọn để thành viên không trừu tượng, trình biên dịch sẽ cho phép các lớp con không triển khai thực hiện, làm lộ nguy cơ gọi thực hiện giả. –

Trả lời

29

Thú vị - Tôi không chắc chắn bạn có thể. Tuy nhiên, nếu đây là mã thực của bạn, bạn có bao giờ muốn triển khai GetEnumerator() không chung chung theo bất kỳ cách nào khác hơn bằng cách gọi một mã chung không?

Tôi muốn làm điều này:

abstract class MyList<T> : IEnumerable<T> 
{ 
    public abstract IEnumerator<T> GetEnumerator(); 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Đó giúp bạn tiết kiệm từ sự nhàm chán vì phải thực hiện nó trong mỗi lớp có nguồn gốc - mà sẽ không có nghi ngờ đều sử dụng việc thực hiện tương tự.

+2

Tôi không có lý do gì để nghĩ rằng nó sẽ được thực hiện theo bất kỳ cách nào khác ... nhưng bạn không bao giờ biết. +1 – BCS

+2

Hãy bình luận của bạn - Tôi có thể đã hiểu sai nó ...chỉnh sửa để sửa chữa nó, và tìm thấy mã giống hệt của bạn - vì vậy đã xóa ;-p –

14

Trong khi một thành viên giao diện rõ ràng có thể không được trừu tượng (hoặc ảo), nó có thể được thực hiện trong điều khoản của một trừu tượng (hoặc ảo) thành viên 1:

public abstract class Foo: IEnumerable { 
    IEnumerator IEnumerable.GetEnumerator() { 
     return getEnumerator();  
    } 

    protected abstract IEnumerator getEnumerator(); 
} 

public class Foo<T>: Foo, IEnumerable<T> { 
    private IEnumerable<T> ie; 
    public Foo(IEnumerable<T> ie) { 
     this.ie = ie; 
    } 

    public IEnumerator<T> GetEnumerator() { 
     return ie.GetEnumerator(); 
    } 

    protected override IEnumerator getEnumerator() { 
     return GetEnumerator(); 
    } 

    //explicit IEnumerable.GetEnumerator() is "inherited" 
} 

tôi đã tìm thấy sự cần thiết cho điều này trong gõ mạnh mẽ một phần của ASP.NET MVC 3, mà không hỗ trợ các kiểu định nghĩa kiểu generic (theo như tôi biết).

+0

Tôi thấy mình phải sử dụng giải pháp này là tốt. Cảm ơn! (Jon Skeets trả lời có ý nghĩa trong ví dụ được cung cấp, nhưng nếu không có mối quan hệ đơn giản như vậy thì đây có vẻ là giải pháp an toàn nhất theo như tôi biết). – AnorZaken

0

Tôi đã có một trường hợp phức tạp hơn một chút, nơi tôi muốn một lớp cơ sở để thực hiện giao diện không chung chung một cách rõ ràng và một lớp dẫn xuất thực hiện giao diện chung.

Giao diện:

public interface IIdentifiable<TKey> : IIdentifiable 
{ 
    TKey Id { get; } 
} 

public interface IIdentifiable 
{ 
    object Id { get; } 
} 

Tôi giải quyết nó bằng cách tuyên bố một phương pháp getter trừu tượng trong lớp cơ sở và cho phép thực hiện rõ ràng gọi nó là:

public abstract class ModelBase : IIdentifiable 
{ 
    object IIdentifiable.Id 
    { 
     get { return GetId(); } 
    } 

    protected abstract object GetId(); 
} 

public class Product : ModelBase, IIdentifiable<int> 
{ 
    public int ProductID { get; set; } 

    public int Id 
    { 
     get { return ProductID; } 
    } 

    protected override object GetId() 
    { 
     return Id; 
    } 
} 

Lưu ý rằng các lớp cơ sở không có phiên bản đã nhập của Id có thể gọi.

1

Bạn thực sự có thể làm điều đó, bằng cách buộc một lớp, mà xuất phát từ một lớp trừu tượng, để thực hiện một giao diện, và vẫn cho phép nó để lựa chọn như thế nào để thực hiện giao diện mà - ngầm hay rõ ràng:

namespace Test 
{ 
    public interface IBase<T> 
    { 
     void Foo(); 
    } 

    public abstract class BaseClass<T> 
     where T : IBase<T> // Forcing T to derive from IBase<T> 
    { } 

    public class Sample : BaseClass<Sample>, IBase<Sample> 
    { 
     void IBase<Sample>.Foo() { } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Sample sample = new Sample(); 

      // Error CS1061 'Sample' does not contain a definition for 'Foo' 
      // and no extension method 'Foo' accepting a first argument of type 'Sample' 
      // could be found(are you missing a using directive or an assembly reference ?) 
      sample.Foo(); 

      (sample as IBase<Sample>).Foo(); // No Error 
     } 
    } 
} 
Các vấn đề liên quan