Я думаю, вы можете сделать это, используя пользовательские атрибуты и анализы кода roslyn. Позвольте мне набросать решение. Это должно, по крайней мере, решить первую проблему, когда вы инициализируетесь литералом.
Сначала вам потребуется специальный атрибут, который относится к структурам, чтобы код анализ, чтобы иметь возможность знать допустимый диапазон:
[AttributeUsage(System.AttributeTargets.Struct)]
public class MinMaxSizeAttribute : Attribute
{
public int MinVal { get; set;}
public int MaxVal { get; set;}
public MinMaxSizeAttribute()
{
}
}
Что вы делаете здесь вы храните минимальный и максимальное значение атрибут. Таким образом, вы можете использовать это позже в анализах исходного кода.
Теперь применим этот атрибут в объявлении структуры:
[MinMaxSize(MinVal = 0, MaxVal = 100)]
public struct Foo
{
//members and implicit conversion operators go here
}
Теперь информация о типе для структуры 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)
{
}
}
Это голый костный скелет для участия в анализе кода. Анализатор регистрирует для анализа заданий:
context.RegisterSyntaxNodeAction(AnalyzeSyntaxTree, SyntaxKind.SimpleAssignmentExpression);
Для объявления переменных вам нужно будет зарегистрировать для другого 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);
}
}
}
}
}
Что анализатор делает, проверяет, установлен ли тип на левой стороне имеет MinMaxSize
, связанный с ним, и если да, он проверяет, с правой стороны является буквальным. Когда он является литералом, он пытается получить целочисленное значение и сравнивает его с MinVal
и MaxVal
, связанными с типом. Если значения превышают этот диапазон, он сообщит об ошибке диагностики.
Обратите внимание, что весь этот код в основном не проверен. Он компилирует и передает некоторые базовые тесты. Но он предназначен только для иллюстрации возможного решения. Для получения дополнительной информации см. Rsolyn Docs
Второй корпус, который вы хотите использовать, более сложный, потому что вам нужно будет применить dataflow analyzes, чтобы получить значение x
.
его невозможно. byte - это тип с диапазоном 255. Я не думаю, что вы можете ограничить это во время компиляции или создать нестандартный тип. –
@M.kazemAkhgary Это может быть возможно, изменив Roslyn, хотя я не уверен, насколько жестким или разумным будет –
Интересный вопрос! В Visual Studio 2013, если я ставлю слишком большое значение, Intellisense знает. Интересно, есть ли способ определить класс с подобной поддержкой Intellisense или если это испечено. –