Ich denke, Sie können dies tun, indem Sie benutzerdefinierte Attribute und Roslyn-Code-Analysen verwenden. Lassen Sie mich eine Lösung skizzieren. Dies sollte zumindest den ersten Anwendungsfall lösen, in dem Sie mit einem Literal initialisiert werden.
Zuerst würden Sie ein benutzerdefiniertes Attribut benötigen, die auf Ihre Struktur gilt der Code zu ermöglichen Analysen der Lage sein, den gültigen Bereich zu wissen:
[AttributeUsage(System.AttributeTargets.Struct)]
public class MinMaxSizeAttribute : Attribute
{
public int MinVal { get; set;}
public int MaxVal { get; set;}
public MinMaxSizeAttribute()
{
}
}
Was Sie tun, ist hier speichern Sie die minimalen und maximalen Wert in ein Attribut Auf diese Weise können Sie dies später in den Quellcodeanalysen verwenden.
nun dieses Attribut auf die Strukturdeklaration gelten:
[MinMaxSize(MinVal = 0, MaxVal = 100)]
public struct Foo
{
//members and implicit conversion operators go here
}
Nun ist die Typinformationen für die Struktur Foo
enthält den Wertebereich. Das nächste, was Sie brauchen, ist eine DiagnosticAnalyzer
, um Ihren Code zu analysieren.
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)
{
}
}
Dies ist das Skelett des bloßen Knochens, um an Codeanalysen teilzunehmen. Der Analysator registriert Zuordnungen analysieren:
context.RegisterSyntaxNodeAction(AnalyzeSyntaxTree, SyntaxKind.SimpleAssignmentExpression);
Für Variablendeklarationen würden Sie für einen anderen SyntaxKind
registrieren müssen, aber der Einfachheit halber werde ich ein hier bleiben.
Ermöglicht bei den Analysen Logik einen Blick:
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);
}
}
}
}
}
Was der Analysator tut, ist, auf der linken Seite, wenn der Typ prüft ein MinMaxSize
mit ihm verbunden hat und wenn ja, prüft sie, ob die rechte Seite ist ein Literal. Wenn es sich um ein Literal handelt, versucht es den ganzzahligen Wert zu erhalten und vergleicht es mit den MinVal
und MaxVal
, die dem Typ zugeordnet sind. Wenn die Werte diesen Bereich überschreiten, wird ein Diagnosefehler gemeldet.
Bitte beachten Sie, dass dieser Code größtenteils noch nicht getestet wurde. Es kompiliert und bestanden einige grundlegende Tests. Aber es soll nur eine mögliche Lösung veranschaulichen. Weitere Informationen finden Sie unter Rsolyn Docs
Der zweite Fall, den Sie abdecken möchten, ist komplexer, weil Sie dataflow analyzes anwenden müssen, um den Wert x
zu erhalten.
ist nicht möglich. Byte ist ein Typ mit einem Bereich von 255. Ich denke nicht, dass Sie dies in der Kompilierzeit begrenzen oder benutzerdefinierten Typ erstellen können. –
@M.kazemAkhgary Es könnte möglich sein, Roslyn zu modifizieren, obwohl ich mir nicht sicher bin, wie schwer oder vernünftig das wäre. –
Interessante Frage! Wenn ich in Visual Studio 2013 einen Literalwert einlege, der zu groß ist, weiß der Intellisense. Ich frage mich, ob es eine Möglichkeit gibt, eine Klasse mit ähnlicher Intellisense-Unterstützung zu definieren, oder ob das gebacken ist. –