-
Notifications
You must be signed in to change notification settings - Fork 582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ImporterOptions.TryToUseExistingAssemblyRefs option #422
Conversation
…y existing AssemblyRefs whenever possible
could you open issues or discussions in dnlib reop? if someone want to introduce improvements or anything else may cause breaking change, there should be a place to discuss it. |
I reported this issue so many years ago(at least 5 years). using System;
using System.Reflection;
using System.Text;
using dnlib.DotNet;
public class AssemblyVersionMapper : ImportMapper
{
readonly ModuleDef module;
readonly Assembly asm;
public AssemblyVersionMapper(ModuleDef module, Assembly asm = null)
{
this.module = module;
this.asm = asm;
}
public override TypeRef Map(Type source)
{
if (source.Assembly == asm)
return null;
if (GetBestAssemblyRef(source.Assembly) is not AssemblyRef asmRef)
return null;
GetTypeNamespaceAndName_TypeDefOrRef(source, out var @namespace, out var name);
if (source.IsNested)
return new TypeRefUser(module, @namespace, name, Map(source.DeclaringType));
return new TypeRefUser(module, @namespace, name, asmRef);
}
public static void GetTypeNamespaceAndName_TypeDefOrRef(Type type, out string @namespace, out string name)
{
name = Unescape(type.Name) ?? string.Empty;
if (!type.IsNested)
@namespace = type.Namespace ?? string.Empty;
else
{
string declTypeFullName = Unescape(type.DeclaringType.FullName);
string typeFullName = Unescape(type.FullName);
if (declTypeFullName.Length + 1 + name.Length == typeFullName.Length)
@namespace = string.Empty;
else
@namespace = typeFullName.Substring(declTypeFullName.Length + 1, typeFullName.Length - declTypeFullName.Length - 1 - name.Length - 1);
}
}
internal static string Unescape(string name)
{
if (string.IsNullOrEmpty(name) || name.IndexOf('\\') < 0)
return name;
var sb = new StringBuilder(name.Length);
for (int i = 0; i < name.Length; i++)
{
if (name[i] == '\\' && i < name.Length - 1 && IsReservedTypeNameChar(name[i + 1]))
sb.Append(name[++i]);
else
sb.Append(name[i]);
}
return sb.ToString();
}
static bool IsReservedTypeNameChar(char c) => c switch
{
',' or '+' or '&' or '*' or '[' or ']' or '\\' => true,
_ => false,
};
AssemblyRef GetBestAssemblyRef(Assembly asm)
{
foreach (var asmRef in module.GetAssemblyRefs())
{
if (asmRef.FullName == asm.FullName)
return asmRef;
}
string publicKeyToken = asm.FullName.Substring(asm.FullName.LastIndexOf('=') + 1);
if (publicKeyToken is "b77a5c561934e089" or "b03f5f7f11d50a3a" or "31bf3856ad364e35" or "cc7b13ffcd2ddd51" or "7cec85d7bea7798e" or "adb9793829ddae60" or "0a613f4dd989e8ae")
{
foreach (var asmRef in module.GetAssemblyRefs())
{
if (asmRef.Name == asm.GetName().Name && asmRef.Version.ToString() is "2.0.0.0" or "3.0.0.0" or "3.5.0.0" or "4.0.0.0")
return asmRef;
}
}
return module.GetAssemblyRef(asm.GetName().Name); ;
}
} I didn't use |
Opened. |
Done. |
Thanks, merged! |
Add ImporterOptions.TryToUseExistingAssemblyRefs option to use already existing AssemblyRefs whenever possible
if .net 2.0 3.5 assembly is loaded in .net 4.x runtime, and we use importer to import something, that will cause both v2.0 reference assemblies and v4.0 reference assemblies appear in AssemblyRef table in saved assembly