Encuentre recursos no utilizados en una solución .NET

¿Cómo se puede encontrar icons, imágenes y cadenas no utilizados en archivos .resx que pueden haber quedado huérfanos y ya no se necesitan?

Esta no es información que un algoritmo pueda calcular confiablemente. El progtwig inspeccionado podría obtener una lista de todos los recursos y hacer algo con ellos, como dejar que el usuario elija entre varios icons.

Su mejor opción es, probablemente, buscar todas las referencias a su API de acceso a recursos e inspeccionarlas manualmente. Usando grep / sed es posible que pueda reducir los sitios que debe inspeccionar manualmente al manejar todos los “fáciles” donde se usa una cadena simple.

Recientemente, ResXManager 1.0.0.41 agregó una función para mostrar el número de referencias a un recurso de cadena.

Captura de pantalla que muestra la nueva columna de referencia

No pude encontrar ninguna solución existente que buscar referencias de recursos de cadenas en archivos XAML y eliminar por lotes los que no se usan.

Así que escribí esto: https://github.com/Microsoft/RESX-Unused-Finder

Captura de pantalla de RESX Unused Finder

Busca en el directorio de un proyecto las referencias a los recursos de cadena, luego muestra una lista de los que no pudo encontrar una coincidencia. Puede especificar una plantilla para buscar para que pueda encontrar referencias en archivos XAML.

Creé una extensión gratuita de código abierto VS que busca imágenes no utilizadas en un proyecto, acaba de publicar la primera versión: https://github.com/jitbit/vs-unused-image-finder

Como todavía no podía encontrar una solución simple y rápida , encontré al menos una solución que me permite obtener el resultado que estoy buscando, incluso si lleva algo de tiempo (ideal para una tarde de domingo flojo).

La solución incluye Visual Studio .NET 2010 y ReSharper (estoy usando la versión 7.1) y es como la siguiente.

Solución paso-a-paso

1.) Haga clic con el botón derecho en su archivo RESX principal en VS.NET y seleccione “Buscar usos” en el menú contextual:

enter image description here

Esto abrirá la ventana de “Buscar resultados” de ReSharper.

2.) Haga doble clic en cada aparición en la ventana de la solución:

enter image description here

Esto abrirá la ventana del código fuente con el recurso.

3.) Cambie el nombre de este recurso desde la ventana del código fuente:

enter image description here

Aparecerá el cuadro de diálogo “Renombrar recurso” de ReSharper.

4.) Dale al recurso un nuevo nombre con un prefijo único . En mi ejemplo, esto es “TaskDialog_”:

enter image description here

Renombrará tanto el recurso como la clase de acceso / envoltura de C # generada automáticamente.

5.) Repita los pasos 2, 3 y 4 anteriores para todos los recursos en la ventana “Usos”.

6.) Abra el archivo RESX en el editor de recursos de Visual Studio y seleccione todos los archivos sin el prefijo:

enter image description here

7.) Ahora haga clic en el botón “Eliminar recurso” en la parte superior de la ventana o simplemente presione la tecla Supr :

enter image description here

Finalmente tiene un archivo RESX con solo los recursos utilizados en su archivo.

8.) (Opcional) Si tiene recursos en varios idiomas (por ejemplo, “Resources.de.resx” para el alemán), repita los pasos 7 y 8 para esos archivos RESX, también.

Advertencia

Tenga en cuenta que esto no funcionará si accede a sus cadenas a través de los Resources clase C #, fuertemente tipados y generados automáticamente.

Recientemente construí una herramienta que detecta y elimina recursos de cadenas no utilizados. Usé la información en esta publicación como referencia. Es posible que la herramienta no sea perfecta, pero cumple con la parte de levantamiento de objetos pesados ​​y será útil si tiene un proyecto grande con una larga historia. Utilizamos esta herramienta internamente para consolidar archivos de recursos y eliminar recursos no utilizados (eliminamos más de 4.000 recursos de 10.000).

Puede mirar el código fuente o simplemente instalar ClickOnce desde aquí: https://resxutils.codeplex.com/

Tuve un problema similar. Varias miles de cadenas de recursos que había creado para una tabla de traducción, muchas de las cuales ya no eran necesarias o referencia por código. Con alrededor de 180 archivos de código dependientes, no había forma de que fuera a examinar manualmente cada cadena de recursos.

El siguiente código (en vb.net) pasará por su proyecto buscando recursos huérfanos (en los recursos del proyecto , no en los recursos de formularios individuales ). Me tomó alrededor de 1 minuto para mi proyecto. Se puede modificar para buscar cadenas, imágenes o cualquier otro tipo de recurso.

En resumen, eso;

  • 1) Utiliza el archivo de proyecto de solución para reunir todos los módulos de código incluidos y los agrega en una sola variable de cadena;
  • 2) Pasa por todos los objetos de recursos del proyecto y crea una lista (en mi caso) de aquellos que son cadenas;
  • 3) ¿Busca una cadena los códigos de cadena de recursos de búsqueda en la variable de texto de proyecto combinada;
  • 4) Informa objetos de recursos que no están referenciados.

La función devuelve los nombres de los objetos en el portapapeles de Windows para pegarlos en una hoja de cálculo o como una matriz de lista de los nombres de los recursos.

editar : ejemplo de llamada en el módulo: 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 

Uso ReSharper para encontrar campos de recursos no utilizados y luego los elimino manualmente si el proyecto contiene poca cantidad de recursos. Algunos guiones cortos se pueden usar si ya tenemos una lista de elementos no utilizados.

La solución es la siguiente:

  • mostrar todos los miembros no utilizados como se describe en este artículo
  • eliminación temporal * .Designer.cs de las máscaras de archivos generados (ReSharper → Opciones → CodeInspection → GeneratedCode)
  • También comente o elimine comentarios (que indica que el código se genera automáticamente) desde la parte superior del archivo Designer.cs adjunto al archivo de recursos.

Tendrás una lista de todos los recursos no utilizados, a la izquierda para eliminarlos de resx.

He estado considerando esto yo mismo y creo que tengo dos opciones. Ambos se basan en el hecho de que utilizo un método auxiliar para extraer el recurso requerido de los archivos de recursos.

  1. Explotación florestal
    Agregue un código al método o métodos “getresource” para que cada vez que se acceda a un recurso, la clave de recurso se escriba en un registro. Luego intente acceder a cada parte del sitio (un script de prueba podría ser útil aquí). Las entradas de registro resultantes deberían proporcionar una lista de todas las claves de recurso activas, el rest puede eliminarse.

  2. Análisis de código
    Estoy viendo si T4 es capaz de trabajar a través de la solución y crear una lista de todas las referencias al método de ayuda “getresource”. La lista resultante de claves estará activa, el rest se puede eliminar.

Hay limitaciones de ambos métodos. El método de registro es tan bueno como el código cubierto por la prueba y el análisis del código puede no encontrar siempre las claves en lugar de las cadenas que contienen las claves, por lo que se requerirá algún trabajo manual adicional.

Creo que probaré ambos. Te dejaré saber cómo va.

Cambie el nombre de su directorio de imagen actual y luego cree uno nuevo, realice una búsqueda de hallazgos en VS dentro de su ruta de imagen, es decir, ‘/ content / images’, seleccione todas las imágenes usadas y arrástrelas a la nueva carpeta de imágenes. Luego puede excluir el directorio anterior del proyecto o simplemente eliminarlo.