2013-08-15 39 views
9

Trước hết, xin lỗi cho danh hiệu, nhưng tôi không thể nghĩ về bất cứ điều gì tốt hơn ...Generics và gọi phương pháp quá tải từ lớp khác biệt - ưu tiên vấn đề

Vấn đề của tôi có thể được trình bày bởi mẫu mã đơn giản:

public static class Test<T> 
{ 
    public static int GetInt(T source) 
    { 
     return Convert.ToInt32(source); 
    } 
} 

public static class Convert 
{ 
    public static int ToInt32(byte source) 
    { 
     return 30; 
    } 

    public static int ToInt32(object source) 
    { 
     return 10; 
    } 
} 

Tại sao Console.WriteLine(Test<byte>.GetInt(20)); in 10, thay vì 30?

Tôi luôn nghĩ rằng generics trong .NET được JIT giải quyết trong suốt thời gian chạy. Tại sao jitter không đủ thông minh, để tìm ra rằng có phương pháp ToInt32(byte), phù hợp với loại thông số byte của chúng tôi ở đây?

Hành vi này làm cho Convert phương thức lớp tĩnh kết quả cuộc gọi trong hoạt động boxing/unboxing cho các loại đơn giản.

+0

'test .GetInt (byte.Parse ("20"))' trả 10 cũng mà tôi tìm thấy người lạ, Cửa sổ đồng hồ nói loại là đối tượng {byte} mà có thể đưa ra một số đầu mối như những gì đang có trên – Sayse

Trả lời

7

Trình biên dịch phải quyết định thời gian biên dịch để chọn phương pháp nào. Nó không phát ra bất kỳ mã nào để quyết định thời gian chạy của hai quá tải để chọn. Vì bạn chưa cung cấp bất kỳ bằng chứng nào cho trình biên dịch C# mà GetInt(T source) chỉ hoạt động với cấu trúc byte, trình biên dịch phải chọn quá tải khác.

Hoặc để tôi đặt nó ở một góc độ khác: nếu bạn loại bỏ quá tải ToInt32(object), chương trình của bạn không thể biên dịch được.

+0

Có cách nào để làm cho nó gọi phương thức 'byte' (hoặc nói chung, phương pháp tốt nhất có sẵn)? – MarcinJuraszek

+0

kiểm tra typeof (T) == typeof (byte) + được truyền thành byte nếu đúng là cách duy nhất – Vitaly

+0

@MarcinJuraszek: Môn đấm bốc có thực sự là vấn đề không? – Steven

0

Trình biên dịch quyết định thời gian biên dịch thực thi phương pháp nào.

Tôi nhìn xuyên qua Reflector cho IL đang và thấy điều này -

.method public hidebysig static int32 GetInt(!T source) cil managed 
{ 
    .maxstack 1 
    .locals init (
     [0] int32 CS$1$0000) 
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: box !T 
    L_0007: call int32 ConsoleApplication1.Convert::ToInt32(object) <-- HERE 
    L_000c: stloc.0 
    L_000d: br.s L_000f 
    L_000f: ldloc.0 
    L_0010: ret 
} 

Như đã đề cập bởi Jon Skeethere, bạn có thể thực hiện cuộc gọi đến phương pháp byte sử dụng dynamic cung cấp gõ thông tin tại thời gian thực hiện thay vì thời gian biên dịch.

public static class Test<T> 
{ 
    public static int GetInt(T source) 
    { 
     dynamic dynamicSource = source; 
     return Convert.ToInt32(dynamicSource); 
    } 
}