2010-10-31 20 views
10

Làm thế nào tôi có thể kiểm tra/đánh giá chính xác loại T mà không có đối tượng cho T. Tôi biết câu hỏi của tôi có thể khó hiểu nhưng xem xét ...Generics: Làm thế nào để kiểm tra chính xác loại T, không có đối tượng cho T

public abstract class Business 
    { 
     public abstract string GetBusinessName(); 
    } 

    public class Casino : Business 
    { 
     public override string GetBusinessName() 
     { 
      return "Casino Corp"; 
     } 
    } 

    public class DrugStore : Business 
    { 
     public override string GetBusinessName() 
     { 
      return "DrugStore business"; 
     } 
    } 


    public class BusinessManager<T> where T : Business 
    { 
     private Casino _casino; 
     private DrugStore _drugStore; 

     public string ShowBusinessName() 
     { 
      string businessName; 
      if (T == Casino) // Error: How can I check the type? 
      { 
       _casino = new Casino(); 
       businessName = _casino.GetBusinessName(); 
      } 
      else if (T == DrugStore) // Error: How can I check the type? 
      { 
       _drugStore = new DrugStore(); 
       businessName = _drugStore.GetBusinessName(); 
      } 

      return businessName; 

     } 
    } 

Tôi chỉ muốn có một cái gì đó như thế này trên máy khách.

protected void Page_Load(object sender, EventArgs e) 
    { 
     var businessManager = new BusinessManager<Casino>(); 
     Response.Write(businessManager.ShowBusinessName()); 

     businessManager = new BusinessManager<DrugStore>(); 
     Response.Write(businessManager.ShowBusinessName()); 
    } 

Lưu ý rằng tôi thực sự không tạo đối tượng thực tế cho Sòng bạc và Nhà thuốc khi tôi gọi BusinessManager, tôi chỉ chuyển nó làm hạn chế kiểu chung của lớp. Tôi chỉ cần biết chính xác loại nào tôi đang chuyển BusinessManager để biết chính xác loại nào để khởi tạo. Cảm ơn ...

PS: Tôi không muốn tạo BusinessManager cụ thể riêng cho Casino và Drugstore ..

Bạn cũng có thể bình luận về thiết kế .. thanks ..

BỔ SUNG: và những gì nếu Casino lớp và nhà thuốc là một lớp trừu tượng =)

Trả lời

9

Bạn nên làm

public class BusinessManager<T> where T : Business, new() 
... 

T _business = new T(); 
string businessName = _business.GetBusinessName(); 
return businessName; 
+0

hmm .. bị bệnh thử phương pháp này .. – CSharpNoob

+0

Cảm ơn mọi người vì tất cả các câu trả lời của bạn! nhưng tôi đã cho CHECK đến người đầu tiên đề xuất phương pháp tiếp cận phù hợp hơn .. cảm ơn! – CSharpNoob

+0

hey nếu tôi làm cho lớp Casino và DrugStore cũng là một lớp trừu tượng, có cách giải quyết nào về vấn đề này không? – CSharpNoob

12

Bạn có thể viết

if(typeof(T) == typeof(Casino)) 

nhưng thực sự loại logic này là một mùi mã.

Dưới đây là một khoảng cách này:

public class BusinessManager<T> where T : Business, new() { 
    private readonly T business; 
    public BusinessManager() { 
     business = new T(); 
    } 
} 

nhưng cá nhân tôi muốn

public class BusinessManager<T> where T : Business { 
    private readonly T business; 
    public BusinessManager(T business) { 
     this.business = business; 
    } 

    public string GetBusinessName() { 
     return this.business.GetBusinessName(); 
    } 
} 
+0

yeah, đây là C++ ish, có cách nào khác để làm điều này không? cảm ơn – CSharpNoob

+0

@CSharpNoob: Vui lòng xem chỉnh sửa của tôi. – jason

+0

cảm ơn nó hoạt động! :) – CSharpNoob

1

Bạn có thể làm một cái gì đó như thế này:

if (typeof(T) == typeof(SomeType)) 
{ 
    // Same 
} 
2

Tôi không biết về cú pháp của C#, nhưng nó không thể làm:

public class BusinessManager<T> where T : Business, new() 
    { 
     private T _business; 

     public string ShowBusinessName() 
     { 
      string businessName; 
      _business = new T(); 
      return _business.GetBusinessName(); 
     } 
    } 
+0

có kiboard nào trong java không? –

+0

Bạn cần thêm ', new()' sau ': Business' –

+0

@Albin Sunnanbo: Đã sửa lỗi. Mặc dù nó chỉ làm nổi bật thực tế là tôi không biết C#. –

1

định nghĩa một lớp BusinessManager như dưới đây:

public class BusinessManager<T> where T : Business 
{ 
    Business biz; 
    public BusinessManager() 
    { 
     biz = new T(); 
    } 

    public string ShowBusinessName() 
    { 
     return biz.GetBusinessName(); 
    } 
} 

và sử dụng nó như dưới đây:

var businessManager = new BusinessManager<Casino>(); 
    Response.Write(businessManager.ShowBusinessName()); 

    var anotherBusinessManager = new BusinessManager<DrugStore>(); 
    Response.Write(businessManager.ShowBusinessName()); 

Cách bạn sử dụng, bạn sẽ mất gói gọn

2

Vì những người khác đã cho thấy nhiều câu trả lời cho câu hỏi đầu tiên của bạn, tôi muốn giải quyết câu hỏi thứ hai: thiết kế.

1. Vai trò của BusinessManager

vai trò thực tế của lớp BusinessManager trong ví dụ của bạn không phải là quá rõ ràng. Vì lớp này là chung, và nó không nên quan tâm đến loại thực tế của T, sau đó nó không có gì hơn là thêm một lớp không cần thiết khác giữa lớp Business và phần còn lại của chương trình.

Nói cách khác, bạn chỉ có thể sử dụng:

Business casino = new Casino(); 
Response.Write(casino.GetBusinessName()); 

Business drugStore = new DrugStore(); 
Response.Write(drugStore.GetBusinessName()); 

Bao bì này trong một lớp generic không giúp bạn rất nhiều. Mặt khác, nếu bạn muốn có một số chức năng phổ biến cho tất cả các lớp này, bạn có thể thêm nó trực tiếp vào lớp trừu tượng của bạn, hoặc trích xuất một giao diện và tạo các phương thức mở rộng cho giao diện đó.

2. Sử dụng các thuộc tính cho thu khí

Điều thứ hai, sử dụng tài sản là thích hợp hơn khi bạn có một phương thức getter đơn giản. Nói cách khác, bạn nên thay thế GetBusinessName() phương pháp với một tài sản Name (Tôi cũng bỏ qua "kinh doanh" từ tên vì nó không phải là cần thiết:

public interface IBusiness 
{ 
    string Name { get; } 
} 

public abstract class Business : IBusiness 
{ 
    public abstract string Name { get; } 
} 

public class Casino : Business 
{ 
    public override string Name 
    { 
     get { return "Casino Corp"; } 
    } 
} 

public class DrugStore : Business 
{ 
    public override string Name 
    { 
     get { return "DrugStore business"; } 
    } 
} 

Và sau đó bạn có thể sử dụng nó như thế này:

IBusiness casino = new Casino(); 
Response.Write(casino.Name); 

IBusiness drugStore = new DrugStore(); 
Response.Write(drugStore.Name); 

Ngoài ra, bạn có thể thấy rằng tôi đã giới thiệu một giao diện IBusiness. Lý do làm như vậy là cho phép bạn triển khai giao diện này theo nhiều cách khác nhau ngay bây giờ, bạn sẽ cố gắng lấy tất cả các lớp học của mình từ lớp trừu tượng Business và cố gắng trích xuất nhiều chức năng phổ biến trong lớp trừu tượng (đó là mục đích của lớp).

Nhưng trích xuất nhiều chức năng thông thường đi kèm với chi phí: luôn có khả năng bạn sẽ cần tạo lớp học không được bắt nguồn từ Business. Nếu bạn đang truy cập tất cả các phương thức này thông qua giao diện IBusiness thì các phần khác của chương trình của bạn sẽ không quan tâm liệu việc triển khai đó có bắt nguồn từ Business hay không.

+0

về cơ bản của nó chỉ là một Wrapper Class, (nó kết thúc tốt đẹp cả Casino và DrugStore và phơi bày các phương pháp chung của chúng) nhưng như bạn nói, tôi có thể đặt các phương thức phổ biến trực tiếp vào lớp cơ sở, cảm ơn cho đầu vào .. – CSharpNoob

1

Trong VB.net, bạn có thể sử dụng hàm GetType giả trên một tham số kiểu chung để nhận đối tượng Kiểu phản chiếu. Tôi đoán C# nên có một tương đương. Nếu vì lý do nào đó bạn không thể sử dụng một cái gì đó như thế, bạn có thể tạo một mảng gồm 0 phần tử của kiểu mong muốn, và sau đó kiểm tra kiểu mảng đó. Điều đó có lẽ sẽ rẻ hơn việc khởi tạo một yếu tố của loại không xác định.

2

Vì GetBusinessName thực sự áp dụng cho loại và không phải là trường hợp của loại, bạn có thể xem xét sử dụng DescriptionAttribute (hoặc BusinessNameAttribute của riêng bạn) thay vì thuộc tính được ghi đè và có BusinessManager của bạn lấy tên doanh nghiệp từ thuộc tính.

[Description("Casino Corp")] 
public class Casino : Business 
{ 
} 

Bây giờ bạn không còn cần phải khởi tạo doanh nghiệp chỉ để lấy tên của doanh nghiệp. Để có được mô tả, bạn sử dụng:

public string ShowBusinessName() 
    { 
     var attribute = Attribute.GetCustomAttribute(typeof(T), typeof(DescriptionAttribute)) as DescriptionAttribute; 
     if (attribute == null) 
      return "Unknown business"; 

     return attribute.Description; 
    } 
Các vấn đề liên quan