如何在 .resx 文件中查找可能已“孤立”且不再需要的未使用图标、图像、字符串?
10 回答
最近ResXManager 1.0.0.41添加了一个功能来显示对字符串资源的引用数。
我找不到任何可以在 XAML 文件中搜索字符串资源引用并批量删除未使用的资源引用的现有解决方案。
所以我写了这个:https ://github.com/Microsoft/RESX-Unused-Finder
它在项目目录中搜索对字符串资源的引用,然后显示找不到匹配项的列表。您可以指定要搜索的模板,以便它可以在 XAML 文件中找到引用。
我创建了一个免费的开源 VS 扩展,用于查找项目中未使用的图像,刚刚发布了第一个版本:https ://marketplace.visualstudio.com/items?itemName=Jitbit1.VSUnusedImagesFinder
这不是算法可以可靠计算的信息。被检查的程序可以获取所有资源的列表并对它们做一些事情,比如让用户从几个图标中进行选择。
您最好的选择可能是搜索对您选择的资源访问 API 的所有引用并手动检查这些引用。使用grep
/sed
您可以通过处理所有使用简单字符串的“简单”站点来减少必须手动检查的站点。
由于我还没有找到一个简单而快速的解决方案,我至少找到了一个解决方案,它可以让我得到我正在寻找的结果,即使它需要一些时间(非常适合慵懒的周日下午)。
该解决方案涉及 Visual Studio .NET 2010 和 ReSharper(我使用的是 7.1 版),如下所示。
分步解决方案
1.)右键单击 VS.NET 中的主 RESX 文件,然后从上下文菜单中选择“查找用法”:
这将打开 ReSharper 的“查找结果”窗口。
2.)双击解决方案窗口中的每个事件:
这将打开包含资源的源代码窗口。
3.)从源代码窗口中重命名此资源:
它将调出 ReSharper 的“重命名资源”对话框。
4.)给资源一个带有唯一前缀的新名称。在我的示例中,这是“TaskDialog_”:
它将重命名资源以及自动生成的 C# 包装器/访问类。
5.)对“使用”窗口中的所有资源重复上述步骤 2、3 和 4。
6.)在 Visual Studio 的资源编辑器中打开 RESX 文件并选择所有不带前缀的文件:
7.)现在单击窗口顶部的“删除资源”按钮或只需按下Del键:
您终于有了一个 RESX 文件,其中仅包含文件中实际使用的资源。
8.)(可选)如果您有多种语言的资源(例如,德语的“Resources.de.resx”),也对这些 RESX 文件重复步骤 7 和 8。
警告
请注意,如果您通过强类型、自动生成的 C# 类以外的方式访问字符串,这将不起作用Resources
。
我最近构建了一个工具来检测和删除未使用的字符串资源。我使用这篇文章中的信息作为参考。该工具可能并不完美,但它完成了繁重的工作,如果您有一个历史悠久的大项目,它将很有用。我们在内部使用此工具来整合资源文件,并删除未使用的资源(我们从 10,000 个资源中删除了 4,000 多个资源)。
您可以查看源代码,或者从这里安装 ClickOnce:https ://resxutils.codeplex.com/
我有一个类似的问题。我为翻译表创建了数千个资源字符串,其中许多不再需要或通过代码引用。由于有大约 180 个依赖代码文件,我无法手动检查每个资源字符串。
以下代码(在 vb.net 中)将通过您的项目查找孤立资源(在项目资源中,而不是任何单个表单的资源中)。我的项目花了大约 1 分钟。可以修改它以查找字符串、图像或任何其他资源类型。
总而言之;
- 1) 使用解决方案项目文件收集所有包含的代码模块并将它们附加到单个字符串变量中;
- 2)循环遍历所有项目资源对象,并创建一个列表(在我的情况下)是字符串;
- 3) 是否在组合项目文本变量中查找资源字符串代码的字符串搜索;
- 4) 报告未被引用的资源对象。
该函数返回 Windows 剪贴板上的对象名称,以便粘贴到电子表格中或作为资源名称的列表数组。
编辑:模块中的示例调用:modTest
? modTest.GetUnusedResources("C:\Documents and Settings\me\My Documents\Visual Studio 2010\Projects\myProj\myProj.vbproj", True, true)
'project file is the vbproj file for my solution
Public Function GetUnusedResources(projectFile As String, useClipboard As Boolean, strict As Boolean) As List(Of String)
Dim myProjectFiles As New List(Of String)
Dim baseFolder = System.IO.Path.GetDirectoryName(projectFile) + "\"
'get list of project files
Dim reader As Xml.XmlTextReader = New Xml.XmlTextReader(projectFile)
Do While (reader.Read())
Select Case reader.NodeType
Case Xml.XmlNodeType.Element 'Display beginning of element.
If reader.Name.ToLowerInvariant() = "compile" Then ' only get compile included files
If reader.HasAttributes Then 'If attributes exist
While reader.MoveToNextAttribute()
If reader.Name.ToLowerInvariant() = "include" Then myProjectFiles.Add((reader.Value))
End While
End If
End If
End Select
Loop
'now collect files into a single string
Dim fileText As New System.Text.StringBuilder
For Each fileItem As String In myProjectFiles
Dim textFileStream As System.IO.TextReader
textFileStream = System.IO.File.OpenText(baseFolder + fileItem)
fileText.Append(textFileStream.ReadToEnd)
textFileStream.Close()
Next
' Debug.WriteLine(fileText)
' Create a ResXResourceReader for the file items.resx.
Dim rsxr As New System.Resources.ResXResourceReader(baseFolder + "My Project\Resources.resx")
rsxr.BasePath = baseFolder + "Resources"
Dim resourceList As New List(Of String)
' Iterate through the resources and display the contents to the console.
For Each resourceValue As DictionaryEntry In rsxr
' Debug.WriteLine(resourceValue.Key.ToString())
If TypeOf resourceValue.Value Is String Then ' or bitmap or other type if required
resourceList.Add(resourceValue.Key.ToString())
End If
Next
rsxr.Close() 'Close the reader.
'finally search file string for occurances of each resource string
Dim unusedResources As New List(Of String)
Dim clipBoardText As New System.Text.StringBuilder
Dim searchText = fileText.ToString()
For Each resourceString As String In resourceList
Dim resourceCall = "My.Resources." + resourceString ' find code reference to the resource name
Dim resourceAttribute = "(""" + resourceString + """)" ' find attribute reference to the resource name
Dim searchResult As Boolean = False
searchResult = searchResult Or searchText.Contains(resourceCall)
searchResult = searchResult Or searchText.Contains(resourceAttribute)
If Not strict Then searchResult = searchResult Or searchText.Contains(resourceString)
If Not searchResult Then ' resource name no found so add to list
unusedResources.Add(resourceString)
clipBoardText.Append(resourceString + vbCrLf)
End If
Next
'make clipboard object
If useClipboard Then
Dim dataObject As New DataObject ' Make a DataObject clipboard
dataObject.SetData(DataFormats.Text, clipBoardText.ToString()) ' Add the data in string format.
Clipboard.SetDataObject(dataObject) ' Copy data to the clipboard.
End If
Return unusedResources
End Function
我使用 ReSharper 查找未使用的资源字段,然后如果项目包含少量资源,则手动删除它们。如果我们已经有未使用项目的列表,可以使用一些简短的脚本。
接下来是解决方案:
- 显示本文所述的所有未使用的成员
- 从生成的文件掩码中临时删除 *.Designer.cs (ReSharper → 选项 → CodeInspection → GeneratedCode)
- 还要从附加到资源文件的 Designer.cs 文件顶部注释或删除注释(表示代码是自动生成的)。
您将获得所有未使用资源的列表,以便将它们从 resx 中删除。
我自己一直在考虑这个问题,我相信我有两个选择。这两者都依赖于我使用辅助方法从资源文件中提取所需资源的事实。
记录
向“getresource”方法或方法添加一些代码,以便每次访问资源时,将资源键写入日志。然后尝试访问站点的每个部分(测试脚本在这里可能会有所帮助)。生成的日志条目应该给出所有活动资源键的列表,其余的可以被垃圾。代码分析
我正在查看T4是否能够完成解决方案并创建对“getresource”辅助方法的所有引用的列表。结果键列表将处于活动状态,其余的可以删除。
这两种方法都有局限性。日志记录方法仅与测试覆盖的代码一样好,并且代码分析可能并不总是找到键而不是包含键的字符串,因此那里需要一些额外的手动工作。
我想我会尝试两个。我会让你知道情况如何。
重命名您当前的图像目录,然后创建一个新目录,在 VS 中进行文件查找搜索您的图像路径,即“/content/images”,多选所有使用的图像并将它们拖到新的图像文件夹中。然后,您可以从项目中排除旧目录,或者将其删除。