【发布时间】:2021-03-02 01:21:35
【问题描述】:
如何在 .resx 文件中查找可能已“孤立”且不再需要的未使用图标、图像、字符串?
【问题讨论】:
如何在 .resx 文件中查找可能已“孤立”且不再需要的未使用图标、图像、字符串?
【问题讨论】:
最近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。 p>
警告
请注意,如果您通过强类型、自动生成的 C# 类 Resources 以外的方式访问字符串,这将不起作用。
【讨论】:
我最近构建了一个工具来检测和删除未使用的字符串资源。我使用这篇文章中的信息作为参考。该工具可能并不完美,但它完成了繁重的工作,如果您有一个历史悠久的大型项目,它将很有用。我们在内部使用此工具来整合资源文件,并删除未使用的资源(我们从 10,000 个资源中删除了 4,000 多个资源)。
您可以查看源代码,或者直接从这里安装 ClickOnce:https://resxutils.codeplex.com/
【讨论】:
我遇到了类似的问题。我为翻译表创建了数千个资源字符串,其中许多不再需要或通过代码引用。由于有大约 180 个依赖代码文件,我无法手动遍历每个资源字符串。
以下代码(在 vb.net 中)将通过您的项目查找孤立资源(在 项目资源 中,而不是任何单个表单的资源)。我的项目花了大约 1 分钟。可以修改它以查找字符串、图像或任何其他资源类型。
总结一下;
该函数返回 Windows 剪贴板上的对象名称,以便粘贴到电子表格中或作为资源名称的列表数组。
edit:模块中的示例调用: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 来查找未使用的资源字段,然后如果项目包含少量资源,则手动删除它们。如果我们已经有未使用项目的列表,可以使用一些简短的脚本。
接下来是解决办法:
您将获得所有未使用资源的列表,以便将它们从 resx 中删除。
【讨论】:
我自己一直在考虑这个问题,我相信我有两个选择。这两者都依赖于我使用辅助方法从资源文件中提取所需资源的事实。
日志记录
将一些代码添加到“getresource”方法或方法中,以便每次访问资源时,将资源键写入日志。然后尝试访问站点的每个部分(测试脚本在这里可能会有所帮助)。生成的日志条目应提供所有活动资源键的列表,其余的可以被垃圾。
代码分析
我正在查看T4 是否能够完成解决方案并创建对“getresource”辅助方法的所有引用的列表。生成的键列表将处于活动状态,其余的可以删除。
这两种方法都有局限性。日志记录方法仅与测试涵盖的代码一样好,并且代码分析可能并不总是找到键而不是包含键的字符串,因此那里需要一些额外的手动工作。
我想我会尝试两者。我会告诉你进展如何。
【讨论】:
重命名您当前的图像目录,然后创建一个新目录,在 VS 中进行文件查找搜索您的图像路径,即“/content/images”,多选所有使用的图像并将它们拖到新图像中文件夹。 然后,您可以从项目中排除旧目录,或者直接删除它。
【讨论】: