I am trying to rename a field in a generic class. Given this test class:
internal class GenericClass<T>
{
private readonly T _value;
public GenericClass(T value)
{
_value = value;
}
}
I can locate and rename the _value field with this:
var genericType = mod.Types[2];
var genericField = genericType.Fields[0];
genericField.Name = "_valueRenamed";
And I can locate a MemberRef to a field with this name, as used in the class constructor, with:
var genericTypeCtorIl = genericType.Methods[0].Body.Instructions;
var genericFieldRef = genericTypeCtorIl[6].Operand as MemberRef;
With this a runtime exception occurs within the constructor because genericFieldRef still points to a field named _value. Only if I manually rename genericFieldRef will the code run correctly.
I've noticed that:
genericField.DeclaringType is a TypeDef GenericTest.GenericClass`1, while
genericFieldRef.DeclaringType is a TypeSpec GenericTest.GenericClass`1<T>.
I've also tried genericFieldRef.Resolve() in the hope of linking MemberRefs to FieldDefs but it returns null. I don't think I quite grasp the nuances around generic types. What would be a good way to resolve a generic MemberRef back to its FieldDef, or to consistently rename a generic field?
Edit - complete test code:
using System.Reflection;
using dnlib.DotNet;
namespace GenericTest
{
internal class Program
{
static void Main(string[] args)
{
/* Rename GenericTest-renamed.exe back to GenericTest.exe
Construct classes; the modified module will fail here */
new GenericClass<string>(string.Empty);
new NonGenericClass(string.Empty);
/* Load current assembly */
var path = Assembly.GetExecutingAssembly().Location;
var opts = new ModuleCreationOptions(CLRRuntimeReaderKind.CLR);
var modCtx = ModuleDef.CreateModuleContext();
var mod = ModuleDefMD.Load(path, opts);
mod.Context = modCtx;
/* Locate and rename field in GenericClass */
var genericType = mod.Types[2];
var genericField = genericType.Fields[0];
genericField.Name = "_valueRenamed";
var genericTypeCtorIl = genericType.Methods[0].Body.Instructions;
var genericFieldRef = genericTypeCtorIl[6].Operand as MemberRef;
//genericFieldRef.Name = "_valueRenamed"; // Will crash if without
/* Locate and rename field in NonGenericClass */
var nonGenericType = mod.Types[3];
var nonGenericField = nonGenericType.Fields[0];
nonGenericField.Name = "_valueRenamed";
//var nonGenericTypeCtorIl = nonGenericType.Methods[0].Body.Instructions;
//var nonGenericFieldDef = nonGenericTypeCtorIl[6].Operand as FieldDef; // Not needed
mod.Write("GenericTest-renamed.exe");
}
}
internal class GenericClass<T>
{
private readonly T _value;
public GenericClass(T value)
{
_value = value;
}
}
internal class NonGenericClass
{
private readonly object _value;
public NonGenericClass(object value)
{
_value = value;
}
}
}
I am trying to rename a field in a generic class. Given this test class:
I can locate and rename the
_valuefield with this:And I can locate a
MemberRefto a field with this name, as used in the class constructor, with:With this a runtime exception occurs within the constructor because
genericFieldRefstill points to a field named_value. Only if I manually renamegenericFieldRefwill the code run correctly.I've noticed that:
genericField.DeclaringTypeis aTypeDefGenericTest.GenericClass`1, whilegenericFieldRef.DeclaringTypeis aTypeSpecGenericTest.GenericClass`1<T>.I've also tried
genericFieldRef.Resolve()in the hope of linkingMemberRefs toFieldDefs but it returns null. I don't think I quite grasp the nuances around generic types. What would be a good way to resolve a genericMemberRefback to itsFieldDef, or to consistently rename a generic field?Edit - complete test code: