use*_*661 12 c# coercion compile-time
我正在尝试定义一个结构,该结构使用具有有限数字范围的变量,以及来自整数的隐式强制.如果任何常量或其他硬编码值与此结构一起使用,我希望能够强制构建错误.
这是我想要完成的一个例子.
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
Run Code Online (Sandbox Code Playgroud)
理想情况下,我希望能够将数字限制在1到99之间,以便MyStruct s = 50; 但是MyStruct s = 150; 导致编译时错误,如上面的字节b和d.
我发现了一种类似于不同语言的东西,但不是C#.
我认为您可以通过使用自定义属性和 roslyn 代码分析来做到这一点。让我画出一个解决方案。这至少应该解决使用文字初始化的第一个用例。
首先,您需要一个适用于您的结构的自定义属性,以允许代码分析能够知道有效范围:
[AttributeUsage(System.AttributeTargets.Struct)]
public class MinMaxSizeAttribute : Attribute
{
public int MinVal { get; set;}
public int MaxVal { get; set;}
public MinMaxSizeAttribute()
{
}
}
Run Code Online (Sandbox Code Playgroud)
您在这里所做的是将最小值和最大值存储在属性中。这样您就可以在稍后的源代码分析中使用它。
现在将此属性应用于结构声明:
[MinMaxSize(MinVal = 0, MaxVal = 100)]
public struct Foo
{
//members and implicit conversion operators go here
}
Run Code Online (Sandbox Code Playgroud)
现在结构体的类型信息Foo包含值范围。接下来您需要DiagnosticAnalyzer分析您的代码。
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)
{
}
}
Run Code Online (Sandbox Code Playgroud)
这是参与代码分析的基本框架。分析器注册来分析分配:
context.RegisterSyntaxNodeAction(AnalyzeSyntaxTree, SyntaxKind.SimpleAssignmentExpression);
Run Code Online (Sandbox Code Playgroud)
对于变量声明,您需要注册一个不同的变量SyntaxKind,但为了简单起见,我将在这里坚持使用一个。
我们看一下分析逻辑:
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);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
分析器所做的是检查左侧的类型是否与其关联MinMaxSize,如果是,则检查右侧是否是文字。当它是文字时,它会尝试获取整数值并将其与与类型关联的MinVal和进行比较。MaxVal如果值超出该范围,它将报告诊断错误。
请注意,所有这些代码大部分都未经测试。它编译并通过了一些基本测试。但这只是为了说明一种可能的解决方案。有关更多信息,请查看Rsolyn 文档
您想要涵盖的第二种情况更为复杂,因为您需要应用数据流分析来获取 的值x。