草庐IT

c# - Roslyn 是编译时表达式检查的正确工具吗?

coder 2024-05-30 原文

我有一个工具包,其中有许多方法经常使用 Expression<Func<T,TProperty>>作为参数。有些只能是单级 ( o=>o.Name ),而有些可以是多级 ( o=>o.EmployeeData.Address.Street )。

我想开发一些东西(MSBuild 任务?Visual Studio 插件?希望是第一个)来读取所有用户的 .cs 文件,如果给定的参数不是属性表达式(而是类似 o=>o.Contains("foo") 的东西),则会出现构建错误), 或者如果在只允许单级的情况下给出了多级表达式。

我尝试先查看已编译的 IL 代码,但由于表达式树是 C# 编译器的“技巧”,在 IL 中,我所看到的只是创建表达式实例等,而我可以检查每个 if仅创建了 MemberExpressions(以及它们的正确数量),它不是很好。

然后我想到了 Roslyn。 是否可以用 Roslyn 编写类似这样的东西?

最佳答案

是的,我认为 Roslyn 及其代码问题正是解决此问题的正确工具。使用它们,您可以在键入和创建在 Visual Studio 中显示为其他错误的错误(或警告)时分析代码。

我曾尝试创建这样的代码问题:

[ExportSyntaxNodeCodeIssueProvider("PropertyExpressionCodeIssue", LanguageNames.CSharp, typeof(InvocationExpressionSyntax))]
class PropertyExpressionCodeIssueProvider : ICodeIssueProvider
{
    [ImportingConstructor]
    public PropertyExpressionCodeIssueProvider()
    {}

    public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
    {
        var invocation = (InvocationExpressionSyntax)node;

        var semanticModel = document.GetSemanticModel(cancellationToken);

        var semanticInfo = semanticModel.GetSemanticInfo(invocation, cancellationToken);

        var methodSymbol = (MethodSymbol)semanticInfo.Symbol;

        if (methodSymbol == null)
            yield break;

        var attributes = methodSymbol.GetAttributes();

        if (!attributes.Any(a => a.AttributeClass.Name == "PropertyExpressionAttribute"))
            yield break;

        var arguments = invocation.ArgumentList.Arguments;
        foreach (var argument in arguments)
        {
            var lambdaExpression = argument.Expression as SimpleLambdaExpressionSyntax;
            if (lambdaExpression == null)
                continue;

            var parameter = lambdaExpression.Parameter;
            var memberAccess = lambdaExpression.Body as MemberAccessExpressionSyntax;
            if (memberAccess != null)
            {
                var objectIdentifierSyntax = memberAccess.Expression as IdentifierNameSyntax;

                if (objectIdentifierSyntax != null
                    && objectIdentifierSyntax.PlainName == parameter.Identifier.ValueText
                    && semanticModel.GetSemanticInfo(memberAccess, cancellationToken).Symbol is PropertySymbol)
                    continue;
            }

            yield return
                new CodeIssue(
                    CodeIssue.Severity.Error, argument.Span,
                    string.Format("Has to be simple property access of '{0}'", parameter.Identifier.ValueText));
        }
    }

    #region Unimplemented ICodeIssueProvider members

    public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxToken token, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

    public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxTrivia trivia, CancellationToken cancellationToken)
    {
        throw new NotImplementedException();
    }

    #endregion
}

用法是这样的:

[AttributeUsage(AttributeTargets.Method)]
class PropertyExpressionAttribute : Attribute
{ }

…

[PropertyExpression]
static void Foo<T>(Expression<Func<SomeType, T>> expr)
{ }

…

Foo(x => x.P);   // OK
Foo(x => x.M()); // error
Foo(x => 42);    // error

上面的代码有几个问题:

  1. 它完全没有优化。
  2. 它可能需要更多的错误检查。
  3. 它不起作用。至少在当前的 CTP 中是这样。靠近末尾的表达式 semanticModel.GetSemanticInfo(memberAccess, cancellationToken).Symbol 始终返回 null。这是因为表达式树的语义在the currently unimplemented features之间。 .

关于c# - Roslyn 是编译时表达式检查的正确工具吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9768233/

有关c# - Roslyn 是编译时表达式检查的正确工具吗?的更多相关文章

  1. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  2. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  3. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  4. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  5. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  6. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  7. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  8. ruby - 检查日期是否在过去 7 天内 - 2

    我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

  9. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  10. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

随机推荐