2013-02-14 24 views
15

Sau khi tái cấu trúc một số mã gần đây, liên quan đến một số đổi tên lớp, một số mã của tôi đã phá vỡ một cách đáng ngạc nhiên. Nguyên nhân là một kiểm tra toán tử "is" không thành công, rằng tôi đã rất ngạc nhiên không phải là lỗi biên dịch hay cảnh báo.C# các lớp tĩnh và toán tử là

chương trình hoàn chỉnh này cho thấy tình hình:

static class ExtensionMethods {} 

class Program { 

    static void Main() { 
     Test("Test"); 
    } 

    public static bool Test(object obj) 
    { 
     return obj is ExtensionMethods; 
    } 
} 

tôi dự kiến ​​sẽ có "obj là ExtensionMethods" để nâng cao một cảnh báo của một số loại, cho rằng ExtensionMethods là một lớp tĩnh.

Trình biên dịch sẽ đưa ra cảnh báo cho toán tử "is" khi đối tượng được thử nghiệm không bao giờ có thể thuộc loại được cung cấp, ví dụ ((string)obj) is System.Uri.

Tôi có quên một trường hợp trong đó điều này thực sự sẽ là một thử nghiệm có ý nghĩa không?

+1

FWIW, ReSharper sẽ khai thác điều này. –

+0

Cho rằng 'đối tượng' được chuyển vào phương thức' Test' không thực sự chỉ định kiểu thời gian biên dịch, tôi không thấy trình biên dịch biết sự khác biệt như thế nào. –

+1

@Robert, không phải lúc nào cũng sai vì không có gì có thể là một thể hiện của một lớp tĩnh? –

Trả lời

11

I was very surprised wasn't a compiler error or warning.

Nó phải có được. Đó là một sự giám sát.

Có một số lỗi giống như liên quan đến các lớp tĩnh. Nếu tôi nhớ lại chính xác, thậm chí có một số kịch bản kỳ lạ mà Vladimir Reshetnikov đã tìm thấy nơi mà nó có thể đưa ra suy luận kiểu suy ra một kiểu tĩnh như là một ràng buộc trên một tham số kiểu.

Dường như cái này, mà tôi đã thấy trước đây, không bao giờ được sửa. Xin lỗi vì sự giám sát.

Am I forgetting a scenario in which this would actually be a meaningful test?

số

1

Tôi lấy một vết nứt ở đây, và mặc dù tôi không thể tìm thấy điều này trong tài liệu tham khảo MSDN, nó xuất hiện như là operatror phụ thuộc vào instantiating một loại để có thể kiểm tra chống lại. Vì các lớp tĩnh không thể được instatiated (vì các lớp tĩnh là các đối tượng được tạo trên ngăn xếp chương trình tại thời gian biên dịch) ...

Ví dụ, nếu bạn làm như sau, bạn sẽ nhận được lỗi sau: gõ"

ExtensionMethods ex; 

Cũng không nếu bạn làm như bên dưới, bạn nhận được lỗi sau: 'không thể tạo một thể hiện của lớp tĩnh'

ExtensionMethods ex2 = new ExtensionMethods(); 

Để chứng minh vấn đề này, đây là một chương trình hoàn chỉnh cho thấy toán tử is.

static class ExtensionMethods { } 

// notice non-static 
class AnotherNonStaticExtensionMethod { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Debug.WriteLine(Test(new AnotherNonStaticExtensionMethod()).ToString()); 
     Debug.WriteLine(Test("Test").ToString()); 
     Debug.WriteLine(Test(4).ToString()); 
    } 

    public static bool Test(object obj) 
    { 
     if (obj is ExtensionMethods) 
     { 
      return true; 
     } 
     else if (obj is AnotherNonStaticExtensionMethod) 
     { 
      return true; 
     } 
     else 
     { 
      return false; 
     } 
    } 
} 

Đây là kết quả sau:

True 
False 
False 

là đối tượng có khả năng kiểm tra đối với một lớp instantiable với báo cáo kết quả đầu tiên - do đó dẫn tôi để tin rằng là nhà điều hành phụ thuộc vào nó. Tôi hy vọng ai đó có thể xác nhận điều này?

Courtesy of NominSim::

From the C# 3.0 specification, section 10.1.1.3:

A static class may not include a class-base specification (§10.1.4) and cannot explicitly specify a base class or a list of implemented interfaces. A static class implicitly inherits from type object.

4

Từ đặc điểm kỹ thuật C# 3.0, phần 10.1.1.3:

A static class may not include a class-base specification (§10.1.4) and cannot explicitly specify a base class or a list of implemented interfaces. A static class implicitly inherits from type object.

Do đó trình biên dịch dường như không nâng cao cảnh báo vì nó không biết rằng is sẽ luôn luôn trả về false. (Một lớp tĩnh "là" một object, và do đó trình biên dịch không biết rằng một object "là" hoặc "là" không phải là một lớp tĩnh tại thời gian biên dịch.) Thực tế nó có khả năng không biết, hoặc ít nhất có thể tìm thấy ra, nhưng dường như nó không chuyên trường hợp đó và kiểm tra.

0

Theo C Thông số kỹ thuật # Ngôn Ngữ:

The is operator is used to dynamically check if the run-time type of an object is compatible with a given type. The result of the operation E is T, where E is an expression and T is a type, is a boolean value indicating whether E can successfully be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion.

A static class may not include a class-base specification (§10.1.4) and cannot explicitly specify a base class or a list of implemented interfaces. A static class implicitly inherits from type object.

Kể từ khi nó được thừa hưởng từ System.Object ngầm, nó có ý nghĩa rằng trình biên dịch không ban hành một cảnh báo.

Mã xác nhận:

var staticBaseType = typeof(B).BaseType; 

Bạn sẽ nhận được một System.Object như các loại cơ sở.

1

câu trả lời Eric Lippert của từ năm 2013 giải thích rằng đây là một lỗi trong Visual C# 5.0 trình biên dịch (và một số phiên bản trước quá). Vấn đề là ở đó với nhà điều hành as, ví dụ: object bad = obj as ExtensionMethods;.

Trong C# 6.0 (từ 2015), và sau đó, bạn nhận được một lỗi thời gian biên dịch (không chỉ là một cảnh báo):

error CS7023: The second operand of an 'is' or 'as' operator may not be static type 'Xxxx'

Tuy nhiên, điều này chỉ đúng nếu bạn chỉ định tính năng nghiêm ngặt, xem another thread for details on how to do that.