2013-07-02 27 views
5

Ok, tôi có một số lớp khác nhau xuất phát từ một lớp cơ sở. Lớp cơ sở này là một phương thức trừu tượng chứa commom.Sử dụng kiểu dẫn xuất trong lớp trừu tượng cơ sở

Một trong các phương pháp là phương pháp Copy, nên có mặt trong tất cả các lớp dẫn xuất, vì vậy, tôi đã đặt nó trong lớp cơ sở. NHƯNG, tôi muốn nó trả lại derived type không phải là cơ sở cũng không phải đối tượng.

Các giải pháp tôi đã cho rằng, đang sử dụng một loại paramter:

abstract class CopyableClass<T> 
{ 
    public abstract T Copy(); 
} 

class DerivedClass : CopyableClass<DerivedClass> 
{ 
    public override DerivedClass Copy() 
    { 
     //do what is needed for copy and return a new DerivedClass 
    } 
} 

Vì vậy, mục đích chính ở đây là để

Hủy bỏ tham số gõ vào lớp cơ sở và vẫn còn làm cho phương thức trả về kiểu dẫn xuất tương ứng.


Một cách giải quyết khác.

Điều tốt nhất tôi có thể làm cho đến nay là một trong những ý kiến ​​dưới đây, nhưng nó vẫn sử dụng một tham số chung

abstract class BaseClass 
{ 
    //base methods not related to deriving type 
} 

interface ICopyable<T> 
{ 
    T Copy(); 
} 

class DerivedClass : BaseClass, ICopyable<DerivedClass> 
{ 
    public DerivedClass Copy() 
    { 
     //do what is needed for copy and return a new DerivedClass 
    } 
} 
+0

Vì vậy, câu hỏi của bạn là gì? – evanmcdonnal

+0

có thể triển khai tốt hơn điều này dưới dạng giao diện chung không? –

+0

cách loại bỏ tham số kiểu trong lớp cơ sở và vẫn làm cho phương thức trả về kiểu dẫn xuất tương ứng. –

Trả lời

4

Bạn có thể không thực sự. Lớp cơ sở không thể biết tất cả các triển khai trong tương lai. Bạn sẽ phải sử dụng một lớp trừu tượng chung chung (như bạn đã làm) gõ hoặc một phương thức chung chung là Copy.

public abstract class CopyableClass 
{ 
    public abstract T Copy<T>() where T : CopyableClass; 
} 

public class DerivedClass : CopyableClass 
{ 
    public override T Copy<T>() 
    { 
     if(typeof(T) != typeof(DerivedClass)) 
      throw new ArgumentException(); 

     // return your copy 
    } 
} 

Hoặc, nếu bạn muốn để khái quát việc kiểm tra kiểu trong lớp cơ sở của bạn:

public abstract class CopyableClass 
{ 
    public T Copy<T>() where T : CopyableClass 
    { 
     if(GetType() != typeof(T)) 
      throw new ArgumentException(); 

     return (T) Copy(); 
    } 

    protected abstract CopyableClass Copy(); 
} 

public class DerivedClass : CopyableClass 
{ 
    protected override CopyableClass Copy() 
    { 
     return // Your copy; 
    } 
} 

Lưu ý rằng phương pháp thứ hai đặt rất nhiều niềm tin vào việc thực hiện các lớp có nguồn gốc như nó sẽ mù quáng cast giá trị trả về của phương thức abstracted. Trình biên dịch sẽ cho phép bạn trả về một kiểu khác, triển khai thực hiện CopyableClass, trong một kiểu có nguồn gốc nhưng nó sẽ là một lỗi thời gian chạy. Đây không phải là vấn đề nếu bạn có quyền kiểm soát tuyệt đối đối với tất cả các triển khai có nguồn gốc (tức là lớp trừu tượng của bạn cũng có một hàm tạo bên trong).

0

Bạn thực sự muốn triển khai bản sao trong lớp cơ sở và yêu cầu trả lại T. Điều này sẽ làm cho bạn gọi nó với một đối số kiểu và nó trả về kiểu đó.

public static T Copy<T>() where T : CopyableClass 
{ 
    T retVal = new T(); 
    // do whatever copying is required 
    return retVal; 
} 

Để gọi điện cho bạn;

DerivedClass d = Copy<DerivedClass>(); 

Mã của bạn để thực sự làm các bản sao có thể làm việc nhiều hơn một chút để làm chung nhưng nó có giá trị nỗ lực đưa cho bạn sẽ có một thực đơn của Copy() mà làm việc cho bất kỳ loại có nguồn gốc. Tôi không biết những gì logic thuộc về phương pháp vì vậy tôi đã chỉ stubbed những điều trên. Ngoài ra, tôi khuyên bạn nên kiểm tra generics nói chung. Chúng thường là lựa chọn tốt nhất cho những thứ như thế này. Nếu triển khai của bạn cần phải là duy nhất cho lớp cơ sở 'giữ nguyên định nghĩa phương thức nhưng làm cho nó trừu tượng và sau đó ghi đè lên nó trong các lớp cơ sở.

0

Điều này sẽ cho phép bạn phân loại lớp cơ sở này thành loại có nguồn gốc và trả lại.

public abstract class BaseClass<TDerived> : where TDerived: BaseClass<TDerived> 
{ 
    public TDerived DoSomethingCommon(string param) 
    { 
     var derivedType = (TElement)this; 
     //do something. 
     return derivedType; 
    } 
} 
0

Giải pháp này liên quan đến tầng lớp trung lưu nhưng tôi nghĩ nội dung của nó phù hợp hơn với những gì bạn đang tìm kiếm. Ít nhất bạn có được lợi ích có thể có khi cô lập mã sao chép của bạn

public abstract class BaseClass 
    { 
    } 

    public abstract class CopyableClass<T> : BaseClass 
     where T: BaseClass, new() 
    { 
     public T Copy() 
     { 
      var copy = new T(); // Creating a new instance as proof of concept 

      return copy; 
     } 
    } 

    public class DerivedClass : CopyableClass<DerivedClass> 
    { 
    }