powershell - C#: eliminación automática de referencias de ensamblaje innecesarias
automation resharper (3)
Estoy trabajando con una gran base de código con una gran cantidad de proyectos, cada uno de los cuales tiene un puñado (y en algunos casos, enorme) cantidad de referencias a otros. Se ha realizado una refactorización sustancial en esta base de código a lo largo del tiempo, y como resultado hay muchos ensambles a los que hacen referencia algunos proyectos solo porque solían contener una clase que desde entonces se ha movido a otra parte; esa clase de cosas.
ReSharper tiene una herramienta integrada en el IDE que permite a los usuarios encontrar código que realmente utiliza una referencia dada para un proyecto determinado. Sin embargo, para convertir esto en una solución, necesitamos hacer que una persona haga clic derecho en cada referencia en cada proyecto y luego verificar si no hay usos y luego eliminarlos, lo cual no es solo un proceso largo sino que también limita con la tortura.
Me gustaría poder automatizar este proceso para que solo lo ejecutemos y se eliminen las referencias innecesarias; entonces quizás podríamos integrarlo en algún tipo de proceso regular para que los errores pasados por alto pudieran ser captados.
Las dos opciones que he pensado serían A) Automatizar ReSharper con Powershell, si es posible, o B) Tal vez los diagramas de dependencia de la Arquitectura de Visual Studio 2010 podrían manejar esto, y tal vez de forma guionizable si tengo suerte.
Mis preguntas son estas:
- ¿Puede ReSharper tener secuencias de comandos para algo como esto?
- ¿La arquitectura VS2010 permite la eliminación de referencias no utilizadas en cualquier tipo de lote / forma automatizada?
Deberías poder hacer esto solo con PowerShell:
1) carga Visual Studio con tu solución
2) compilar toda la solución
3) deja VS en ejecución y comienza powershell.exe
4) tomar una referencia a la instancia en ejecución del DTE de VS desde el ROT (importante: asegúrese de que solo se ejecuta una instancia) si su elevación, powershell también debería ser:
ps> $dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("visualstudio.dte")
5) Pruebe enumerando todos los proyectos en la solución con sus referencias:
ps> $dte.solution.projects | select @{l="name";e={$_.name}}, `
@{l="references";e={$_.object.references|select -exp name}} | ft -auto
... volca todos los nombres y referencias de proyectos ...
6) Ahora, escriba una secuencia de comandos para atravesar la carpeta de solución y proyectos
7) cuando tocas la carpeta bin /, carga el ensamblaje con reflexión solo carga:
$assembly = [reflection.assembly]::reflectiononlyload($dll)
8) obtenga los ensamblajes referenciados reales en su conjunto de salida
$refs = $assembly.getreferencedassemblies()
9) comparar los conjuntos referenciados reales con los ensamblados a los que se hace referencia en el proyecto y eliminar los redundantes mediante el modelo de objetos VS DTE
# example
$currentproj.object.references.item("system.core").remove()
$currentproj.save()
10) ganancia!
Esto funciona porque .net solo enlaza ensamblados a los que realmente se hace referencia en el código. Lo siento, no puedo publicar un ejemplo completo, pero esto debería ser suficiente para comenzar.
-Oisin
No es una solución completa, pero eche un vistazo a las dependencias de Resolver csproj cuando los proyectos también dependan de los ensamblajes del contenedor y Cómo encontrar dependencias de ensamblaje incorrectas a través de PowerShell . Hay una manera de encontrar referencias a otros proyectos y cómo encontrar referencias en un ensamblado.
La segunda parte es la misma que Oisin propuso. El primero es ligeramente diferente: toma las referencias del archivo csproj (tomado como archivo xml y procesado de esta manera).
Tómelo al menos como una inspiración;)
Seguí las instrucciones de @ x0n pero no funcionó bien para mí. Tal vez me estaba perdiendo algo. Tengo que admitir que no pude cargar mi dll
s con ReflectionOnlyLoad
debido a un error COM. Así que los LoadFile
con LoadFile
. Las referencias de ensamblaje proporcionadas por LoadFile
fueron exactamente las mismas cuando LoadFile
el ensamblado con Reflector. Al final, mi secuencia de comandos de PowerShell generó una lista que muestra las referencias que están en el proyecto pero que no las carga el ensamblado. En teoría, se supone que son las referencias "innecesarias". Cuando comencé a eliminarlos, la construcción falló. Por ejemplo, en el caso de mi primer proyecto, la falta de cualquiera de las 4 referencias "innecesarias" haría que fallara la compilación. Reviso el resultado del script de PowerShell y, por ejemplo, enumera " System
". Si lo elimino, el compilador ni siquiera se queja de un montón de " using System;
", pero falla antes de eso, indicando que necesito hacer referencia a ese ensamblado debido a una interfaz ... Por cierto, nuestro proyecto no es un juguete, implica más de 140 dlls (casi la mitad de los cuales es Test nUnit
dll) y pensé que haría algunas tareas de mantenimiento. Mi script (que no va de forma recursiva a las carpetas de proyectos, algunos proyectos contienen más dlls) por lo que quizás alguien pueda usarlo:
`
$ dte = [System.Runtime.InteropServices.Marshal] :: GetActiveObject ("visualstudio.dte")
$binfiles=Get-ChildItem C:/YourSourcePath/bin/debug
$dlls=$binfiles | where { $_.extension -eq ".dll" -and $_.name -like "*YourCompanyName*" }
foreach ($dll in $dlls) {
foreach($prj in $dte.solution.projects) {
if ($prj.Kind -eq "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") {
if ($prj.Properties.Item("OutputFileName").Value -eq $dll.Name) {
$loaded = [reflection.assembly]::LoadFile($dll.FullName)
$refs = $loaded.GetReferencedAssemblies()
Write "============="
Write $dll.Name
Write "-------------"
foreach($pref in $prj.Object.References) {
$found = 0
foreach($ref in $refs) {
if ($ref.Name -eq $pref.Name) {
$found = 1
break;
}
}
if ($found -eq 0) {
Write $pref.Name
}
}
}
}
}
}
`