2008-10-05 36 views
13

Khi tôi thử điều này với một lớp generic nơi this.value là T:Gõ giá trị chung (C#)

if (this.value.GetType() == typeof(int)) 
{ 
    ((int)this.value)++; 
} 
else 
{ 
    throw new InvalidOperationException 
      ("T must be an int to perform this operation"); 
} 

tôi nhận được một lỗi thời gian biên dịch: "Không thể chuyển đổi loại 'T' thành 'int' "

Tôi nên làm gì để thực hiện thao tác tích phân trên this.value khi đó là int?

Lưu ý rằng đây chỉ là một ví dụ. Mã không gõ chuyển đổi với Generics, và "int" chỉ là một ví dụ của một loại cho T.

Trả lời

24

Thật không may, rất khó để thuyết phục trình biên dịch về việc triển khai T cụ thể. Một cách tiếp cận (khó chịu) là truyền đến đối tượng ở giữa (lưu ý điều này sẽ có giá trị hộp và giá trị unbox):

int i = (int)(object)this.value; 
i++; 
this.value = (T)(object)i; 

Xấu xí nhưng nó hoạt động. Trong .NET 3.5 Tôi có một số trình bao bọc tốt hơn cho số học chung, here. Lớp Operator là một phần của MiscUtil; ở mức đơn giản nhất, tôi nghi ngờ AddAlternative sẽ làm việc rất tốt:

this.value = Operator.AddAlternative(this.value, 1); 

này nên suy ra tiềm ẩn < T, int > tự động, hoặc bạn có thể thêm chúng mình:

this.value = Operator.AddAlternative<T,int>(this.value, 1); 

Benefit: Điều này là thích hợp hơn với mã gốc vì nó không thực sự quan tâm đến T ban đầu - nó sẽ làm việc cho bất kỳ loại nào (thậm chí là của riêng bạn) có hỗ trợ "T + (T, int)".

Tôi nghĩ đó cũng là một ChangeType ẩn xung quanh đâu đó trong đó ...

[sửa] Collin K và những người khác làm cho một nhận xét có giá trị về ý nghĩa kiến ​​trúc - nhưng là thực tế có những lúc T thực sự quan trọng lắm ... nhưng tôi đồng ý tránh loại chuyên môn này trừ khi thực sự cần. Điều đó nói rằng (theo nhận xét của tôi về bài viết của Collin), khả năng thực hiện những thứ như số học cơ bản (gia tăng, phân chia Int32, vv) trên (ví dụ) Ma trận <T> [cho T trong thập phân/float/int/double/vv] thường có giá trị cao.

3

Nhập tĩnh C# sẽ không cho phép bạn làm như vậy, nhưng bạn có thể đánh lừa nó bằng cách truyền tới đối tượng. Tôi sẽ không khuyên bạn nên làm điều này, nó có thể cho thấy vấn đề kiến ​​trúc, nhưng anyway:

using System; 

class Foo<T> 
{ 
    public T value; 

    public void Increment() 
    { 
    if (value is int) value = (T)(object)(((int)(object)value)+1); 
    } 
} 

static class Program 
{ 
    static void Main() 
    { 
    Foo<int> x = new Foo<int>(); 
    x.Increment(); 
    x.Increment(); 
     Console.WriteLine(x.value); 
    }  
} 
0

Tôi không nghĩ rằng tôi hiểu những gì bạn đang sau. Nếu bạn đang yêu cầu một cái gì đó là một loại cụ thể, sau đó bạn có lẽ không nên sử dụng Generics. Bạn có thể, nó chỉ có vẻ ngớ ngẩn. Điều này sẽ làm những gì bạn đang yêu cầu, nhưng tôi không khuyên bạn nên.

namespace GenericsOne 
{ 
    using System; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Sample<int> one = new Sample<int>(); 
     one.AddFive(10); 

     // yes, this will fail, it is to show why the approach is generally not a good one. 
     Sample<DateTime> two = new Sample<DateTime>(); 
     two.AddFive(new DateTime()); 
    } 
} 

} 

namespace GenericsOne 
{ 
    using System; 
public class Sample<T> 
{ 
    public int AddFive(T number) 
    { 
     int junk = 0; 

     try 
     { 
      junk = Convert.ToInt32(number); 
     } 
     catch (Exception) 
     { 
      Console.WriteLine("Nope"); 
     } 

     return junk + 5; 
    } 
} 
} 
+0

Điều này không hoạt động, trình biên dịch không thể xác định ToInt32 quá tải để sử dụng. – AnthonyWJones

+0

Có, nó hoạt động tốt. Dán nó vào VS và thử nó. – user25306

12

Theo tôi, mã loại cụ thể trong một lớp chung là mùi mã. Tôi sẽ refactor nó để có được một cái gì đó như thế này:

public class MyClass<T> 
{ 
... 
} 

public class IntClass : MyClass<int> 
{ 
    public void IncrementMe() 
    { 
    this.value++; 
    } 
} 
+2

Có thể - nhưng trong một số trường hợp, số đơn giản hoặc số chia Int32 rất phổ biến trong mã toán chung (ví dụ: Ma trận trong đó T là float/double/decimal/int/etc). Nhưng trong nhiều trường hợp, có: sometihng là chín muồi. –

0

Đây là lý do tại sao tôi thực sự muốn số hoặc hạn chế hoạt động in C#4.

@Marc Gravell của câu trả lời là cách tốt nhất vòng này (+1), nhưng nó là bực bội như thế nào đây là một vấn đề cho Generics.

Các vấn đề liên quan