Skip to content

Instantly share code, notes, and snippets.

@unarist
Last active July 5, 2016 11:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unarist/418a07ec15e03f8da4d6f6907d43e020 to your computer and use it in GitHub Desktop.
Save unarist/418a07ec15e03f8da4d6f6907d43e020 to your computer and use it in GitHub Desktop.
Mono.Cecilだけでアセンブリをマージする
Action<T> GetAssignMethod<T>(string field, object value)
{
var arg = Expression.Parameter(typeof(T));
var body = Expression.Assign(Expression.Field(arg, field), Expression.Constant(value));
return (Action<T>)Expression.Lambda(typeof(Action<T>), body, arg).Compile();
}
void MoveItems<T>(ICollection<T> src, ICollection<T> dest, Func<T,bool> filter = null)
{
var items = filter != null ? src.Where(filter).ToList() : src.ToList();
items.ForEach(x => { src.Remove(x); dest.Add(x); });
}
void VisitTypes(IEnumerable<TypeDefinition> rootset, Action<TypeDefinition> action)
{
var types = new Stack<TypeDefinition>(rootset);
while (types.Any())
{
var cur = types.Pop();
action(cur);
cur.NestedTypes.ForEach(types.Push);
}
}
void Main()
{
var src = AssemblyDefinition.ReadAssembly(typeof(MyExtensions).Assembly.Location, new ReaderParameters(ReadingMode.Immediate));
var dest = AssemblyDefinition.ReadAssembly(@"R:\hoge.exe");
var src_m = src.MainModule;
var dest_m = dest.MainModule;
// ReadingMode.Immediate でも読んでくれないデータを読み込む(MethodDef.Body)
VisitTypes(src_m.Types, t => t.Methods.ForEach(m => m.Body?.GetHashCode()));
// モジュール間で乗せ換え(moduleを書き換えないといけないもの)
var fixmodule = GetAssignMethod<TypeReference>("module", dest_m);
VisitTypes(src_m.Types, t => t.NestedTypes.ForEach(fixmodule));
src_m.GetTypeReferences().ForEach(fixmodule);
var nativeTypes =
from prop in typeof(TypeSystem).GetProperties()
where prop.PropertyType == typeof(TypeReference)
select (TypeReference)prop.GetValue(src_m.TypeSystem);
nativeTypes.ForEach(fixmodule);
// 名前空間の書き換え
var new_ns = src.Name.Name;
var oldref = dest_m.AssemblyReferences.First(x => x.FullName == src.FullName);
dest_m.GetTypeReferences().Where(t => t.Scope == oldref).ForEach(t => t.Namespace = new_ns);
VisitTypes(src_m.Types, t => t.Namespace = new_ns);
// モジュール間で乗せ換え(Attach/Detachが必要なもの)
MoveItems(src_m.AssemblyReferences, dest_m.AssemblyReferences, t => !dest_m.AssemblyReferences.Any(tt => t.FullName == tt.FullName));
MoveItems(src_m.Types, dest_m.Types, t => !dest_m.Types.Any(tt => t.FullName == tt.FullName));
MoveItems(src_m.Resources, dest_m.Resources);
// 旧アセンブリへの参照を自分自身への参照に
oldref.Name = dest.Name.Name;
oldref.Version = dest.Name.Version;
oldref.Culture = dest.Name.Culture;
oldref.PublicKeyToken = dest.Name.PublicKeyToken;
dest.Write(@"r:\dest.exe");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment