2015-09-30 12 views
12

Tôi đang cố gắng xác định cấu trúc sử dụng biến số với phạm vi số giới hạn và ngầm ép buộc từ ints. Tôi muốn để có thể lực lượng xây dựng lỗi nếu bất kỳ hằng số hoặc giá trị hardcoded khác được sử dụng với cấu trúc này.Bắt buộc một lực ép ngầm hẹp tại thời điểm biên dịch

Đây là ví dụ về những gì tôi đang cố gắng hoàn thành.

byte a = 123; // Allowed 
    byte b = 123123; // Not allowed 
    const int x = 123; 
    const int y = 123123; 
    byte c = x; // Allowed 
    byte d = y; // Not allowed 

Tôi lý tưởng muốn có thể, ví dụ: hạn chế số từ 1 đến 99, sao cho MyStruct s = 50; hoạt động nhưng MyStruct s = 150; gây ra một lỗi thời gian biên dịch như byte b và d ở trên làm.

Tôi tìm thấy something similar for a different language, nhưng không phải cho C#.

+0

không thể thực hiện được. byte là một loại với phạm vi 255. tôi không nghĩ rằng bạn có thể giới hạn này trong thời gian biên dịch hoặc để tạo kiểu tùy chỉnh. –

+0

@M.kazemAkhgary Nó có thể có được bằng cách sửa đổi Roslyn, mặc dù tôi không chắc chắn làm thế nào cứng hoặc hợp lý mà có thể là –

+0

Câu hỏi thú vị! Trong Visual Studio 2013, nếu tôi đặt một giá trị bằng chữ quá lớn, thì Intellisense sẽ biết. Tôi tự hỏi nếu có một cách để xác định một lớp học với sự hỗ trợ Intellisense tương tự hoặc nếu đó là nướng trong. –

Trả lời

0

Tôi nghĩ bạn có thể làm điều này bằng cách sử dụng thuộc tính tùy chỉnh và phân tích mã roslyn. Hãy để tôi phác thảo một giải pháp. Điều này ít nhất nên giải quyết các usecase đầu tiên, nơi bạn khởi tạo với một chữ.

Trước tiên, bạn sẽ cần một thuộc tính tùy chỉnh áp dụng cho cấu trúc của bạn để cho phép các mã phân tích để có thể biết được phạm vi hợp lệ:

[AttributeUsage(System.AttributeTargets.Struct)] 
public class MinMaxSizeAttribute : Attribute 
{ 
    public int MinVal { get; set;} 
    public int MaxVal { get; set;} 
    public MinMaxSizeAttribute() 
    { 
    } 
} 

Những gì bạn làm ở đây là bạn lưu trữ các giá trị min và max trong một thuộc tính. Bằng cách đó bạn có thể sử dụng sau này trong các phân tích mã nguồn.

Bây giờ áp dụng thuộc tính này để khai báo struct:

[MinMaxSize(MinVal = 0, MaxVal = 100)] 
public struct Foo 
{ 
    //members and implicit conversion operators go here 
} 

Bây giờ những thông tin kiểu cho các struct Foo chứa nhiều giá trị. Điều tiếp theo bạn cần là DiagnosticAnalyzer để phân tích mã của bạn.

public class MyAnalyzer : DiagnosticAnalyzer 
{ 
    internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor("CS00042", 
     "Value not allowed here", 
     @"Type {0} does not allow Values in this range", 
     "type checker", 
     DiagnosticSeverity.Error, 
     isEnabledByDefault: true, description: "Value to big"); 
    public MyAnalyzer() 
    { 
    } 

    #region implemented abstract members of DiagnosticAnalyzer 

    public override void Initialize(AnalysisContext context) 
    { 
     context.RegisterSyntaxNodeAction(AnalyzeSyntaxTree, SyntaxKind.SimpleAssignmentExpression); 
    } 

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); 

    #endregion 

    private static void AnalyzeSyntaxTree(SyntaxNodeAnalysisContext context) 
    { 

    } 
} 

Đây là bộ xương xương trần tham gia phân tích mã. Máy phân tích đăng ký để phân tích bài tập:

context.RegisterSyntaxNodeAction(AnalyzeSyntaxTree, SyntaxKind.SimpleAssignmentExpression); 

Đối với khai báo biến bạn sẽ cần phải đăng ký một khác nhau SyntaxKind nhưng vì đơn giản tôi sẽ dính vào ai ở đây.

Cho phép có một cái nhìn tại các phân tích logic:

private static void AnalyzeSyntaxTree(SyntaxNodeAnalysisContext context) 
     { 
      if (context.Node.IsKind(SyntaxKind.SimpleAssignmentExpression)) 
      { 
       var assign = (AssignmentExpressionSyntax)context.Node; 
       var leftType = context.SemanticModel.GetTypeInfo(assign.Left).GetType(); 
       var attr = leftType.GetCustomAttributes(typeof(MinMaxSizeAttribute), false).OfType<MinMaxSizeAttribute>().FirstOrDefault(); 
       if (attr != null && assign.Right.IsKind(SyntaxKind.NumericLiteralExpression)) 
       { 
        var numLitteral = (LiteralExpressionSyntax)assign.Right; 
        var t = numLitteral.Token; 
        if (t.Value.GetType().Equals(typeof(int))) 
        { 
         var intVal = (int)t.Value; 
         if (intVal > attr.MaxVal || intVal < attr.MaxVal) 
         { 
          Diagnostic.Create(Rule, assign.GetLocation(), leftType.Name); 
         } 
        } 
       } 
      } 
     } 

gì phân tích thực hiện là, đang kiểm tra nếu loại ở phía bên trái có một MinMaxSize liên kết với nó và nếu như vậy nó sẽ kiểm tra nếu phía bên phải là một chữ. Khi nó là một chữ, nó cố gắng lấy giá trị số nguyên và so sánh nó với các số MinValMaxVal được kết hợp với loại. Nếu các giá trị vượt quá phạm vi đó, nó sẽ báo cáo lỗi chẩn đoán.

Xin lưu ý rằng tất cả mã này hầu như không được kiểm tra. Nó biên dịch và thông qua một số bài kiểm tra cơ bản. Nhưng nó chỉ có nghĩa là để minh họa một giải pháp có thể. Để biết thêm thông tin, hãy xem Rsolyn Docs

Trường hợp thứ hai bạn muốn bao gồm phức tạp hơn vì bạn sẽ cần phải áp dụng dataflow analyzes để nhận giá trị x.

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