转向资源重构
Move to Resource refactoring
我正在尝试进行自己的移动到资源 重构(就像在 ReSharper 中找到的那样)。在我的 CodeAction.GetChangedDocumentAsync
方法中,我执行以下 3 个步骤:
- 使用
XmlDocument
将我的资源添加到 Resources.resx 文件
- 使用 DTE 运行 自定义工具更新 Resources.Designer.cs 文件
- 用
SyntaxNode.ReplaceNode
新资源的限定标识符替换文字串
第 1 步和第 2 步都可以,但第 3 步不行。如果我删除第 2 步,第 3 步就可以了。
我不知道是因为我混用了 Roslyn 和 DTE,还是因为第 2 步在解决方案中生成了新代码并且我的缓存上下文变得无效。
// Add the resource to the Resources.resx file
var xmlDoc = new XmlDocument();
xmlDoc.Load(resxPath);
XmlNode node = xmlDoc.SelectSingleNode($"//data[@name='{resourceIndentifierName}']");
if (node != null) return;
XmlElement dataElement = xmlDoc.CreateElement("data");
XmlAttribute nameAtt = xmlDoc.CreateAttribute("name");
nameAtt.Value = resourceIndentifierName;
dataElement.Attributes.Append(nameAtt);
XmlAttribute spaceAtt = xmlDoc.CreateAttribute("space", "xml");
spaceAtt.Value = "preserve";
dataElement.Attributes.Append(spaceAtt);
XmlElement valueElement = xmlDoc.CreateElement("value");
valueElement.InnerText = value;
dataElement.AppendChild(valueElement);
XmlNode rootNode = xmlDoc.SelectSingleNode("//root");
Debug.Assert(rootNode != null, "rootNode != null");
rootNode.AppendChild(dataElement);
xmlDoc.Save(resxPath);
// Update the Resources.Designer.cs file
var dte = (DTE2)Package.GetGlobalService(typeof(SDTE));
ProjectItem item = dte.Solution.FindProjectItem(resxPath);
((VSProjectItem) item.Object)?.RunCustomTool();
// Replace the node
SyntaxNode oldRoot = await context.Document.GetSyntaxRootAsync(cancellationToken)
.ConfigureAwait(false);
SyntaxNode newRoot = oldRoot.ReplaceNode(oldNode, newNode);
return context.Document.WithSyntaxRoot(newRoot);
it's because step 2 generate new code in the solution and my cached context becomes invalid
这就是正在发生的事情。当您调用 RunCustomTool
时,visual studio 文件观察器 api 会告诉 roslyn 文件已更新并且 roslyn 会生成一组新的解决方案快照。当您尝试应用代码修复时,roslyn 查看您的代码修复来自的解决方案快照,发现它与当前快照不匹配,因此无法应用。
我正在尝试进行自己的移动到资源 重构(就像在 ReSharper 中找到的那样)。在我的 CodeAction.GetChangedDocumentAsync
方法中,我执行以下 3 个步骤:
- 使用
XmlDocument
将我的资源添加到 Resources.resx 文件
- 使用 DTE 运行 自定义工具更新 Resources.Designer.cs 文件
- 用
SyntaxNode.ReplaceNode
新资源的限定标识符替换文字串
第 1 步和第 2 步都可以,但第 3 步不行。如果我删除第 2 步,第 3 步就可以了。
我不知道是因为我混用了 Roslyn 和 DTE,还是因为第 2 步在解决方案中生成了新代码并且我的缓存上下文变得无效。
// Add the resource to the Resources.resx file
var xmlDoc = new XmlDocument();
xmlDoc.Load(resxPath);
XmlNode node = xmlDoc.SelectSingleNode($"//data[@name='{resourceIndentifierName}']");
if (node != null) return;
XmlElement dataElement = xmlDoc.CreateElement("data");
XmlAttribute nameAtt = xmlDoc.CreateAttribute("name");
nameAtt.Value = resourceIndentifierName;
dataElement.Attributes.Append(nameAtt);
XmlAttribute spaceAtt = xmlDoc.CreateAttribute("space", "xml");
spaceAtt.Value = "preserve";
dataElement.Attributes.Append(spaceAtt);
XmlElement valueElement = xmlDoc.CreateElement("value");
valueElement.InnerText = value;
dataElement.AppendChild(valueElement);
XmlNode rootNode = xmlDoc.SelectSingleNode("//root");
Debug.Assert(rootNode != null, "rootNode != null");
rootNode.AppendChild(dataElement);
xmlDoc.Save(resxPath);
// Update the Resources.Designer.cs file
var dte = (DTE2)Package.GetGlobalService(typeof(SDTE));
ProjectItem item = dte.Solution.FindProjectItem(resxPath);
((VSProjectItem) item.Object)?.RunCustomTool();
// Replace the node
SyntaxNode oldRoot = await context.Document.GetSyntaxRootAsync(cancellationToken)
.ConfigureAwait(false);
SyntaxNode newRoot = oldRoot.ReplaceNode(oldNode, newNode);
return context.Document.WithSyntaxRoot(newRoot);
it's because step 2 generate new code in the solution and my cached context becomes invalid
这就是正在发生的事情。当您调用 RunCustomTool
时,visual studio 文件观察器 api 会告诉 roslyn 文件已更新并且 roslyn 会生成一组新的解决方案快照。当您尝试应用代码修复时,roslyn 查看您的代码修复来自的解决方案快照,发现它与当前快照不匹配,因此无法应用。