- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我试图可靠地比较 ITypeSymbol
的两个实例,在以下情况下可能是最简单和最直接的方法(我在一个更大的项目中遇到了这些问题,并试图尽可能地简化它可能):
我有一个 CSharpCompilation 和这个 SyntaxTree:
namespace MyAssembly
{
public class Foo
{
public Foo(Foo x)
{
}
}
}
我们正在使用 CSharpSyntaxRewriter
遍历树,更改类并更新 Compilation
。在第一次运行中,我们记得第一个构造函数参数的 ITypeSymbol
(在本例中是类本身的类型)。更新编译后,我们再次调用同一个重写器,并第二次从构造函数参数中获取 ITypeSymbol。之后,我比较了我希望代表相同类型 MyAssembly.Foo
的两个 ITypeSymbol。
我的第一个比较方法只是调用 ITypeSymbol.Equals()
方法,但它返回了 false
。它基本上返回 false
,因为我们更改了编译并同时获得了一个新的 SemanticModel
。如果我们不这样做,Equals() 方法实际上会返回 true。
比较 DeclaringSyntaxReferences
(也如此处所述 How to compare type symbols (ITypeSymbol) from different projects in Roslyn? )返回 false,因为我们同时更改了类 Foo
本身。如果构造函数参数的类型为 Bar
并且我们重写了 Bar
,则行为将相同。要验证这一点,只需取消注释行
//RewriteBar(rewriter, compilation, resultTree);
并将代码示例中的构造函数参数类型替换为Bar
。
结论:ITypeSymbol.Equals()
不适用于新的编译和语义模型,并且比较 DeclaringSyntaxReferences
不适用于我们同时更改的类型。(我还使用一种外部程序集测试了行为——在这种情况下,ITypeSymbol.Equals() 对我有用。)
所以我的问题是:
这是我可以重现问题的完整测试程序。只需复制,包括 Roslyn 引用并执行:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace Demo.TypeSymbol
{
class Program
{
static void Main(string[] args)
{
var compilation = (CSharpCompilation) GetTestCompilation();
var rewriter = new Rewriter(changeSomething: true);
var tree = compilation.SyntaxTrees.First(); //first SyntaxTree is the one of class MyAssembly.Foo
rewriter.Model = compilation.GetSemanticModel (tree);
//first rewrite run
var resultTree = rewriter.Visit (tree.GetRoot()).SyntaxTree;
compilation = UpdateIfNecessary (compilation, rewriter, tree, resultTree);
rewriter.Model = compilation.GetSemanticModel (resultTree);
//just for demonstration; comment in to test behaviour when we are rewriting the class Bar -> in this case use Bar as constructor parameter in Foo
//RewriteBar(rewriter, compilation, resultTree);
//second rewrite run
rewriter.Visit (resultTree.GetRoot());
//now we want to compare the types...
Console.WriteLine(rewriter.ParameterTypeFirstRun);
Console.WriteLine(rewriter.ParameterTypeSecondRun);
//=> types are *not* equal
var typesAreEqual = rewriter.ParameterTypeFirstRun.Equals (rewriter.ParameterTypeSecondRun);
Console.WriteLine("typesAreEqual: " + typesAreEqual);
//=> syntax references are not equal
if(rewriter.ParameterTypeFirstRun.DeclaringSyntaxReferences.Any())
{
var syntaxReferencesAreEqual =
rewriter.ParameterTypeFirstRun.DeclaringSyntaxReferences.First()
.Equals(rewriter.ParameterTypeSecondRun.DeclaringSyntaxReferences.First());
Console.WriteLine("syntaxReferencesAreEqual: " + syntaxReferencesAreEqual);
}
//==> other options??
}
private static CSharpCompilation UpdateIfNecessary(CSharpCompilation compilation, Rewriter rewriter, SyntaxTree oldTree, SyntaxTree newTree)
{
if (oldTree != newTree)
{
//update compilation as the syntaxTree changed
compilation = compilation.ReplaceSyntaxTree(oldTree, newTree);
rewriter.Model = compilation.GetSemanticModel(newTree);
}
return compilation;
}
/// <summary>
/// rewrites the SyntaxTree of the class Bar, updates the compilation as well as the semantic model of the passed rewriter
/// </summary>
private static void RewriteBar(Rewriter rewriter, CSharpCompilation compilation, SyntaxTree firstSyntaxTree)
{
var otherRewriter = new Rewriter(true);
var otherTree = compilation.SyntaxTrees.Last();
otherRewriter.Model = compilation.GetSemanticModel(otherTree);
var otherResultTree = otherRewriter.Visit(otherTree.GetRoot()).SyntaxTree;
compilation = UpdateIfNecessary(compilation, otherRewriter, otherTree, otherResultTree);
rewriter.Model = compilation.GetSemanticModel(firstSyntaxTree);
}
public class Rewriter : CSharpSyntaxRewriter
{
public SemanticModel Model { get; set; }
private bool _firstRun = true;
private bool _changeSomething;
public ITypeSymbol ParameterTypeFirstRun { get; set; }
public ITypeSymbol ParameterTypeSecondRun { get; set; }
public Rewriter (bool changeSomething)
{
_changeSomething = changeSomething;
}
public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node)
{
node = (ClassDeclarationSyntax)base.VisitClassDeclaration(node);
//remember the types of the parameter
if (_firstRun)
ParameterTypeFirstRun = GetTypeSymbol (node);
else
ParameterTypeSecondRun = GetTypeSymbol (node);
_firstRun = false;
//change something and return updated node
if(_changeSomething)
node = node.WithMembers(node.Members.Add(GetMethod()));
return node;
}
/// <summary>
/// Gets the type of the first parameter of the first method
/// </summary>
private ITypeSymbol GetTypeSymbol(ClassDeclarationSyntax classDeclaration)
{
var members = classDeclaration.Members;
var methodSymbol = (IMethodSymbol) Model.GetDeclaredSymbol(members[0]);
return methodSymbol.Parameters[0].Type;
}
private MethodDeclarationSyntax GetMethod()
{
return (MethodDeclarationSyntax)
CSharpSyntaxTree.ParseText (@"public void SomeMethod(){ }").GetRoot().ChildNodes().First();
}
}
private static SyntaxTree[] GetTrees()
{
var treeList = new List<SyntaxTree>();
treeList.Add(CSharpSyntaxTree.ParseText(Source.Foo));
treeList.Add(CSharpSyntaxTree.ParseText(Source.Bar));
return treeList.ToArray();
}
private static Compilation GetTestCompilation()
{
var mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
var refs = new List<PortableExecutableReference> { mscorlib };
// I used this to test it with a reference to an external assembly
// var testAssembly = MetadataReference.CreateFromFile(@"../../../Demo.TypeSymbol.TestAssembly/bin/Debug/Demo.TypeSymbol.TestAssembly.dll");
// refs.Add (testAssembly);
return CSharpCompilation.Create("dummyAssembly", GetTrees(), refs);
}
}
public static class Source
{
public static string Foo => @"
// for test with external assembly
//using Demo.TypeSymbol.TestAssembly;
namespace MyAssembly
{
public class Foo
{
public Foo(Foo x)
{
}
}
}
";
public static string Bar => @"
namespace MyAssembly
{
public class Bar
{
public Bar(int i)
{
}
}
}
";
}
}
最佳答案
一种可能是调用 SymbolFinder.FindSimilarSymbols这将在您的新解决方案中为您提供一个按名称和其他一些属性匹配的符号。从那里你可以在你的新编译中使用 Equals。
关于c# - 可靠地将类型符号 (ITypeSymbol) 与 Roslyn 进行比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34243031/
我正在尝试运行以下内容:: Press to see code - name: Snapshot BI nodes hosts: [CLUSTER-BI,CLUSTER-BI-REPL
在这里尝试心理重置:我尝试使用 MSMQ 创建一个可靠、持久的堆栈,但没有成功 所以更一般地说: 我有生产者(一个 web 服务,虽然“只有一个”,但也是多线程的)/消费者(多个进程,根据需要设置)。
试图为分布式系统找到一个商业日志框架。此框架必须允许远程服务器上的 .NET 应用程序记录可以在中央位置收集的消息。如果可能,中央位置应将消息存储在 SQL Server 数据库中。 要求: 能够在远
我正在开发 Restful 服务,我们将在数据库中插入/更新新记录。 由于REST使用HTTP进行通信,而HTTP并不可靠,我担心如果连接失败,请求可能无法发送到服务器。 我在 link 中找到的建议
我正在尝试实现一个页面,员工可以在其中登录并添加、修改、更新工作案例。 我有一个选择列表,其中包含从数据库加载的数据(员工姓名)。在这个数据库中,我有基本信息、用户名、ID、密码、电子邮件。 选择列表
我在 C 代码和 Python 代码之间(偶尔)得到略有不同的计算结果,并设法找到了一个例子。在 Python 中,我得到了这个: >>> print "%.55f" %\ ... (-2.49999
例如如果我将计时器设置为每天午夜到期,如果一个“失火”(例如,由于服务器关闭而不会触发回调)会发生什么?我在文档中找不到它。 有没有办法让这个定时器在服务器重启时立即触发回调? PS:我了解 Quar
我有一组不同长度的非零序列,我正在使用 Keras LSTM 对这些序列建模。我使用 Keras Tokenizer 进行分词(分词从 1 开始)。为了使序列具有相同的长度,我使用了填充。 填充示例:
我遇到了一个非常有趣的可靠 session 行为。我正在使用 netTcp 绑定(bind) + 双工 channel + 可靠 session 。 当我尝试在 channel.faulted 上收听
问题: 给定表 table_a 和 table_b,每当 table_a 更新时,我都需要可靠地(并发地)执行这样的操作: SELECT table_a 中的一些行。 在应用程序代码中计算一些内容。
我们目前的设计 环境 Redis 2.8.17 我们已经实现了我们的可靠队列,使用类似于 redis 文档中描述的模式的模式,在 RPOPLPUSH 下 但是,考虑到其阻塞性质,我们正在使用 BRPO
在我们的 WCF 应用程序中,我正在尝试配置可靠的 session 。 服务: 客户:
我使用这个 Delphi 7 代码来检测 Internet Explorer 是否正在运行: function IERunning: Boolean; begin Result := FindWi
我正在准备构建一个应用程序,该应用程序能够向 GPS 设备发送/接收航路点。通过一些谷歌搜索,我发现了很多可能对此目的有用的库: Java Chaeron GPS GPSLib4J Python Py
我有几个关于 WCF 可靠 session 可靠性的问题: WCF 是否在重试期间重新序列化消息? 2。如果 1 是正确的 - 它是否在消息参数被处理后发生? 3. 如果 2 是正确的 - 是否有任何
对于使用 $(this)[0].defaultValue 来确定文本框值是否已从原始值发生变化的一些反馈,我将不胜感激,例如 //keyUp event if($(this)[0].defaultVa
我正在开发一个具有以下特征的实时应用程序: 数百个客户端将同时插入行/文档,每个客户端每隔几秒插入一行。 大部分仅追加;几乎所有的行/文档,一旦插入,就永远不会改变。 只有当数据刷新到磁盘时,客户端才
场景:最终用户(不受信任的)提供了一个字符串,例如 "Hello, {name}!" .在服务器上,我想以 my_string.format(name="Homer") 的形式对该用户提供的字符串进行
我在推送通知方面遇到一些问题。我们使用 Firebase 来推送通知。问题是我可以在一台 iPhone 上正确接收 PushNotifications,但无法在另一台 iPhone 上接收它们。我在
从 python 到 c++,这是我能得到的最接近 python 的装饰器。 这个解决方案感觉有点像 hack,因为在要装饰的函数之后运行的代码在 Timer 析构函数中是隐式调用的。不过它确实有效。
我是一名优秀的程序员,十分优秀!