c# - Force a narrow implicit coercion at compile time -
i'm trying define struct uses variable restricted range of numbers, , implicit coercion ints. i'd able force build errors if constants or other hardcoded values used struct.
here example of i'm trying accomplish.
byte = 123; // allowed byte b = 123123; // not allowed const int x = 123; const int y = 123123; byte c = x; // allowed byte d = y; // not allowed i ideally able to, example, restrict number 1 99, mystruct s = 50; works mystruct s = 150; causes compile time error bytes b , d above do.
i found something similar different language, not c#.
i think can using custom attributes , roslyn code analyses. let me sketch solution. should @ least solve first usecase initialize literal.
first need custom attribute applies struct allow code analyses able know valid range:
[attributeusage(system.attributetargets.struct)] public class minmaxsizeattribute : attribute { public int minval { get; set;} public int maxval { get; set;} public minmaxsizeattribute() { } } what here store min , max value in attribute. way can use later in source code analyses.
now apply attribute struct declaration:
[minmaxsize(minval = 0, maxval = 100)] public struct foo { //members , implicit conversion operators go here } now type information struct foo contains value range. next thing need diagnosticanalyzer analyze code.
public class myanalyzer : diagnosticanalyzer { internal static diagnosticdescriptor rule = new diagnosticdescriptor("cs00042", "value not allowed here", @"type {0} not allow values in range", "type checker", diagnosticseverity.error, isenabledbydefault: true, description: "value 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) { } } this bare bone skeleton participate in code analyzes. analyzer registers analyze assignments:
context.registersyntaxnodeaction(analyzesyntaxtree, syntaxkind.simpleassignmentexpression); for variable declarations need register different syntaxkind simplicity stick 1 here.
lets have @ analyses 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); } } } } } what analyzer is, checking if type on left side has minmaxsize associated , if checks if right side literal. when literal tries integer value , compares minval , maxval associated type. if values exceeds range report diagnostics error.
please note code untested. compiles , passed basic tests. meant illustrate possible solution. further information have @ rsolyn docs
the second case want covers more complex because need apply dataflow analyzes value of x.
Comments
Post a Comment