2013-04-06 55 views
31

Tôi có một phương pháp mở rộng cho đối tượng đúc an toàn, trông như thế này:IsAssignableFrom, IsInstanceOfType và từ khóa là gì, sự khác biệt là gì?

public static T SafeCastAs<T>(this object obj) { 
    if (obj == null) 
     return default(T); 

    // which one I should use? 

    // 1. IsAssignableFrom 
    if (typeof(T).IsAssignableFrom(obj.GetType())) 
     return (T)obj; 

    // 2. IsInstanceOfType 
    if (typeof(T).IsInstanceOfType(obj)) 
     return (T) obj; 

    // 3. is operator 
    if (obj is T) 
     return (T) obj; 

    return default(T); 
} 

Như bạn thấy, tôi có 3 sự lựa chọn, vì vậy mà một trong tôi nên sử dụng không? Trên thực tế sự khác nhau giữa các nhà cung cấp IsAssignableFrom, IsInstanceOfTypeis là gì?

Trả lời

42

Bạn sử dụng bất cứ điều gì bạn có thông tin cho.

Nếu bạn có một phiên bản và loại tĩnh bạn muốn kiểm tra, hãy sử dụng is.

Nếu bạn không có loại tĩnh, bạn chỉ cần có đối tượng Type, nhưng bạn có một phiên bản bạn muốn kiểm tra, hãy sử dụng IsInstanceOfType.

Nếu bạn không có bản sao và bạn chỉ muốn kiểm tra tính tương thích giữa một ví dụ lý thuyết của TypeType khác, hãy sử dụng IsAssignableFrom. Tuy nhiên, thực sự có vẻ như bạn chỉ đang triển khai lại as operator (ngoại trừ việc bạn cũng sẽ làm việc cho các loại giá trị không thể vô hiệu hóa, thường không phải là một giới hạn lớn).

9

Tôi đoán bạn đang triển khai hiệu quả phiên bản của toán tử as hoạt động với các loại giá trị cũng như các loại tham chiếu.

tôi muốn đi cho:

public static T SafeCastAs<T>(this object obj) 
{ 
    return (obj is T) ? (T) obj : default(T); 
} 

IsAssignableFrom công trình với các loại, và is làm việc với trường. Họ sẽ cung cấp cho bạn kết quả tương tự trong trường hợp của bạn, vì vậy bạn nên sử dụng phiên bản IMHO đơn giản nhất.

Đối với IsInstanceOfType: Điều đó được triển khai theo điều khoản của IsAssignableFrom, do đó sẽ không có sự khác biệt.

Bạn có thể chứng minh rằng bằng cách sử dụng Reflector để nhìn vào định nghĩa của IsInstanceOfType():

public virtual bool IsInstanceOfType(object o) 
{ 
    if (o == null) 
    { 
     return false; 
    } 
    return this.IsAssignableFrom(o.GetType()); 
} 
3

Tôi đoán bạn nên sử dụng "as" thay vì "SafeCastAs" tùy chỉnh của mình. Nhưng điều này sẽ làm việc chỉ cho các lớp học (không cấu trúc), vì vậy nếu bạn muốn sử dụng phương pháp này cho cấu trúc cũng như tôi có thể nhận được nó.

Toán tử "về cơ bản cung cấp cho bạn giống như Type.IsAssignableFrom, vì vậy bạn chỉ có thể giữ" là ", nó sẽ kiểm tra xem bạn có thể đúc obj thành T một cách an toàn không, ngoại trừ trường hợp ngoại lệ. Vì vậy, nó sẽ bao gồm cả kiểm tra trước đó trong phương pháp của bạn. Nhưng bạn nên lưu ý rằng nó không kiểm tra xem bạn có thể gán obj cho T hay không, vì chuyển đổi do người dùng xác định: explicitimplicit từ khóa.

+0

Tôi không chắc chắn khẳng định của bạn ở đây là chính xác. 'typeof (int)' trả về một đối tượng kiểu 'Type' để câu lệnh đầu tiên sẽ thất bại vì đối tượng' Type' rõ ràng không phải là 'int'. Tuy nhiên, nếu bạn thay đổi câu lệnh đầu tiên thành 'a.GetType(). IsInstanceOfType (3)' nó sẽ trả về true. Tôi nghĩ rằng bạn đang sử dụng 'IsInstanceOfType' sai ở đây. –

+0

@ JeffBridgman đúng, tôi đoán tôi chỉ cố gắng để hiển thị sự khác biệt của việc sử dụng hai phương pháp, một cái gì đó như '' ' Console.WriteLine (typeof (int?). IsInstanceOfType (null)); Console.WriteLine (typeof (int?). IsInstanceOfType (1)); Console.WriteLine (typeof (int?). IsAssignableFrom (typeof (int))); '' ' Tôi sẽ xóa một số phần của câu trả lời này. – outcoldman

0

Các chức năng và toán tử này có ý nghĩa khác nhau. Nếu bạn có các đối tượng, bạn luôn có thể nhận được các loại. vì vậy bạn không làm việc trên những gì bạn có, nhưng bạn làm những gì cần phải được thực hiện.

Khi bạn đang làm việc với sự khác biệt về phân cấp lớp rất rõ ràng.

Nhìn vào theo gương

 class ABase 
     { 

     } 

     class BSubclass : ABase 
     { 

     } 
    ABase aBaseObj = new ABase(); 
       BSubclass bSubclassObj = new BSubclass(); 

       ABase subObjInBaseRef = new BSubclass(); 

hoạt động khác nhau mang lại kết quả khác nhau.

typeof(ABase).IsInstanceOfType(aBaseObj) = True 

typeof(ABase).IsInstanceOfType(bSubclassObj) = True 

typeof(ABase).IsInstanceOfType(bSubclassObj) = True 

typeof(BSubclass).IsInstanceOfType(aBaseObj) = False 

bSubclassObj is ABase = True 

aBaseObj is BSubclass = False 

subObjInBaseRef is BSubclass = True 

subObjInBaseRef is BSubclass = True 

typeof(ABase).IsAssignableFrom(typeof(BSubclass)) = True 

typeof(BSubclass).IsAssignableFrom(typeof(ABase))= False 

Trong trường hợp không có phân cấp, có thể là mọi thứ đều giống nhau. Nhưng nếu bạn làm việc với phân cấp, IsAssignableFrom, là và IsInstanceOfType mang lại kết quả khác nhau.

Có nhiều kết hợp có thể được thử. Ví dụ, bạn có thể giới thiệu một lớp C mà không liên quan đến các lớp hiện có trong ví dụ này.

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