Penso che si possa fare ciò usando gli attributi personalizzati e le analisi del codice di Roslyn. Lasciami abbozzare una soluzione. Questo dovrebbe almeno risolvere il primo caso in cui si inizializza con un valore letterale.
In primo luogo si avrebbe bisogno di un attributo personalizzato che si applica al tuo struct per permettere al codice di analisi per essere in grado di conoscere la gamma valida:
[AttributeUsage(System.AttributeTargets.Struct)]
public class MinMaxSizeAttribute : Attribute
{
public int MinVal { get; set;}
public int MaxVal { get; set;}
public MinMaxSizeAttribute()
{
}
}
Quello che fai qui è di memorizzare il minimo e il valore massimo in un attributo. In questo modo puoi usarlo più avanti nelle analisi del codice sorgente.
Ora applicare questo attributo per la dichiarazione struct:
[MinMaxSize(MinVal = 0, MaxVal = 100)]
public struct Foo
{
//members and implicit conversion operators go here
}
Ora le informazioni sul tipo per la struct Foo
contiene il campo di valori. La prossima cosa di cui hai bisogno è una DiagnosticAnalyzer
per analizzare il tuo codice.
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)
{
}
}
Questo è lo scheletro osseo per partecipare alle analisi del codice. L'analizzatore registra per analizzare le assegnazioni:
context.RegisterSyntaxNodeAction(AnalyzeSyntaxTree, SyntaxKind.SimpleAssignmentExpression);
Per dichiarazioni di variabili si avrebbe bisogno di registrarsi per un diverso SyntaxKind
ma per semplicità mi limiterò a uno qui.
Lascia per avere uno sguardo alla logica analisi:
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);
}
}
}
}
}
Che l'analizzatore non è, sta controllando se il tipo sul lato sinistro ha un MinMaxSize
ad esso associato e, se così si controlla se il lato destro è un letterale. Quando si tratta di un valore letterale, tenta di ottenere il valore intero e lo confronta con lo MinVal
e lo MaxVal
associato al tipo. Se i valori superano tale intervallo, verrà segnalato un errore di diagnostica.
Si prega di notare che tutto questo codice è per lo più non testato. Compila e ha passato alcuni test di base. Ma ha il solo scopo di illustrare una possibile soluzione. Per ulteriori informazioni, consultare Rsolyn Docs
Il secondo caso che si desidera coprire è più complesso in quanto è necessario applicare dataflow analyzes per ottenere il valore di x
.
non è possibile. byte è un tipo con un intervallo di 255. Non penso che sia possibile limitarlo in fase di compilazione o per creare un tipo personalizzato. –
@M.kazemAkhgary Potrebbe essere possibile modificando Roslyn, anche se non sono sicuro di quanto sia difficile o ragionevole quello che sarebbe –
Interessante domanda! In Visual Studio 2013, se inserisco un valore letterale troppo grande, l'Intellisense lo sa. Mi chiedo se c'è un modo per definire una classe con supporto Intellisense simile o se è in cottura. –