2009-10-22 15 views
10

Tôi đã tự hỏi nếu điều sau đây là có thể. Tạo một lớp chấp nhận một kiểu vô danh (string, int, decimal, customObject, vv), sau đó có các phương thức quá tải làm các hoạt động khác nhau dựa trên Type. Ví dụPhương pháp quá tải với các loại C#

class TestClass<T> 
{ 
    public void GetName<string>() 
    { 
     //do work knowing that the type is a string  
    } 

    public string GetName<int>() 
    { 
     //do work knowing that the type is an int 

    } 

    public string GetName<int>(int addNumber) 
    { 
     //do work knowing that the type is an int (overloaded)  
    } 

    public string GetName<DateTime>() 
    { 
     //do work knowing that the type is a DateTime 

    } 

    public string GetName<customObject>() 
    { 
     //do work knowing that the type is a customObject type  
    } 

} 

Bây giờ tôi có thể gọi phương thức GetName và vì tôi đã chuyển vào loại khi tôi khởi tạo đối tượng, phương pháp đúng được tìm thấy và thực hiện.

TestClass foo = new TestClass<int>(); 

//executes the second method because that's the only one with a "int" type 
foo.GetName(); 

Điều này có thể hay tôi chỉ mơ?

Trả lời

12

Những gì bạn đang cố gắng làm là có thể như thế này:

class TestClass<T> 
{ 
    public string GetName<T>() 
    { 
     Type typeOfT = typeof(T); 
     if(typeOfT == typeof(string)) 
     { 
      //do string stuff 
     } 
    } 
} 

Trong khi điều này có thể, bạn đang loại đánh bại mục đích của Generics. Điểm của generics là khi loại không vấn đề, vì vậy tôi không nghĩ generics là thích hợp trong trường hợp này.

0

Việc sử dụng các phương pháp tiện ích mở rộng lớp có phù hợp với bạn không?

Bạn về cơ bản có thể thêm các phương thức vào các lớp bạn muốn và sau đó bạn có thể gọi nó theo cùng một cách.

namespace ExtensionMethods 
{ 
    public static class MyExtensions 
    { 
     public static int GetName(this String str) 
     { 
      ... 
     } 
    } 
} 

gọi sử dụng:

myString.GetName(); 
4

"Chuyên ngành" là không thể trong C# cách thức mà nó là trong C++. Trong Generics .NET, một lớp generic hoặc phương thức <T> phải giống nhau cho tất cả các giá trị có thể có của T. Điều này cho phép thời gian chạy tối ưu hóa hai loại tham chiếu khác nhau, ví dụ: > >, chia sẻ cùng một mã ngôn ngữ máy. (Loại giá trị khác nhau nhận được mã máy riêng biệt, nhưng bạn vẫn không thể chuyên môn hóa.)

tôi thấy đôi khi nó giúp tạo ra một giao diện chung hoặc lớp cơ sở như thế này:

abstract class Base<T> { 
    public abstract T GetName(); 
    // any common code goes here that does not require specialization 
} 

Và làm chuyên môn hóa trong nguồn gốc lớp học:

class IntVersion : Base<int> { 
    public override int GetName() { return 1; } 
    public int GetName(int addNumber) { ... } 
} 
class StringVersion : Base<string> { 
    public override string GetName() { return "foo"; } 
} 
class DateTimeVersion : Base<DateTime> { 
    public override DateTime GetName() { return DateTime.Now; } 
} 
+0

+1 Generics! = Templates – user7116

1

Không, điều này là không thể. Những gì bạn đang cố gắng làm là tương tự như chuyên môn mẫu trong C++, đó là (đáng buồn) không thể trong C#.

Bạn cần if/else hoặc bật

typeof(T) 

để gọi triển khai chuyên ngành.

Tuy nhiên, bạn có thể hạn chế các loại T để thể là một lớp (tham khảo giá trị gia tăng) hoặc struct (value) hoặc lớp con của một baseclass nhất định như vậy:

public Foo<T> DoBar<T>() where T : FooBase; 
0

C# không có hỗ trợ cho như vậy.

và đây không phải là cách đúng để thực hiện quá tải phương thức (Error'TestClass 'đã xác định thành viên có tên' GetName 'có cùng loại thông số) miễn là tất cả bên trong <> không phải là một phần của chữ ký phương thức.

3

Chuyên môn không thể thực hiện được trong C#. Điều gần nhất trong C# là sau

public void Example() { 
    public static void Method<T>(T value) { ... } 
    public static void Method(int value){ ... } 
    public static void Method(string) { ... } 
} 

Trình biên dịch C# sẽ thích phương pháp không chung chung hơn phương pháp chung. Điều này có nghĩa là việc gọi với một tham số int sẽ liên kết với quá tải int so với thông số chung.

Example.Method(42); // Method(int) 
Example.Method(new Class1()) // Method<T>(T) 

Điều này sẽ cắn bạn bởi vì điều này không áp dụng khi phương pháp này được gọi chung. Trong trường hợp đó nó sẽ liên kết với quá tải chung bất kể loại nào.

public void Gotcha<T>(T value) { 
    Example.Method(value); 
} 

Gotcha(42); // Still calls Example.Method<T>() 
0

Nếu bạn cần thực hiện công việc cụ thể trong lớp học, thì lớp học của bạn không phải là chung. Bạn có lẽ nên tạo một lớp riêng biệt cho từng loại bạn muốn xử lý. Nếu có một số chức năng có lý do chính đáng để trở thành generic, bạn có thể đặt nó trong một lớp cơ sở chung.

Một ví dụ:

abstract class TestClass<T> 
{ 
    public List<T> Items { get; set; } 

    // other generic (i.e. non type-specific) code 
} 

class IntTestClass : TestClass<int> 
{ 
    public string GetName() 
    { 
     // do work knowing that the type is an int 
    } 

    // other code specific to the int case 
} 

class StringTestClass : TestClass<string> 
{ 
    public string GetName() 
    { 
     // do work knowing that the type is a string 
    } 

    // other code specific to the string case 
} 
0

Như bfree nêu bạn có thể làm điều này với một nếu cây, hoặc nhiều khả năng một tuyên bố chuyển đổi, nhưng tại một số điểm bạn sẽ muốn bạn chỉ có thể viết các phương pháp và để cho Net tìm ra, đặc biệt là nếu bạn phát triển thư viện quá tải theo thời gian.

Các giải pháp có phản ánh, mặc dù nó là khá rẻ hiệu suất-khôn ngoan trong Net:

using System.Reflection; 
... 

public string DoSomething(object val) 
{ 
    // Force the concrete type 
    var typeArgs = new Type[] { val.GetType() }; 

    // Avoid hard-coding the overloaded method name 
    string methodName = new Func<string, string>(GetName).Method.Name; 

    // Use BindingFlags.NonPublic instead of Public, if protected or private 
    var bindingFlags = BindingFlags.Public | BindingFlags.Instance; 

    var method = this.GetType().GetMethod(
     methodName, bindingFlags, null, typeArgs, null); 

    string s = (string)method.Invoke(this, new object[] { val }); 

    return s; 
} 

Bạn đang về cơ bản chỉ nói với khuôn khổ Reflection để đi làm điều đó câu lệnh switch cho bạn.