Introduction
Do you want to do something bad? Very, very bad? Something that every decent programming book warns you against? Good. I'll show you how:).
Put in another way, I'll show you how to read and modify (without reflection) private
variables of another class instance.
And he can't do anything to prevent you from peeping...
Background
Data Abstraction is a very useful concept, and I am in no way going to tell you to drop it. But ... (the way to hell starts with "but", I think) sometimes, you must, absolutely must access this very integer that is stored somewhere deep inside another guy's code. Why? Probably you are implementing custom serialization logic, or object to DB persistence, or pre-condition verification. Or you are just curious...
You can use standard Reflection practices (get
/set
value methods of FieldInfo
).
I'll show you another, probably slightly faster way to accomplish this.
Using the Code
Let's look at a sample class:
class SampleA
{
private int m_value;
private List<string> m_list;
public SampleA(int a)
{
Value = a;
}
public int Value
{
get { return m_value; }
set { m_value = value; }
}
public List<string> List
{
get { return m_list; }
set { m_list = value; }
}
}
Now, how can we access those variables? Take a look:
static void Main(string[] args)
{
SampleA sampleA = new SampleA(17);
AccessorBuilder.GetFieldValueUnboundDelegate<int, SampleA> valueGetter =
AccessorBuilder.CreateGetter<int, SampleA>("m_value");
AccessorBuilder.SetFieldValueUnboundDelegate<int, SampleA> valueSetter =
AccessorBuilder.CreateSetter<int, SampleA>("m_value");
int value = valueGetter(sampleA);
Console.WriteLine(value);
valueSetter(sampleA, 23);
Console.WriteLine(sampleA.Value);
value = valueGetter(sampleA);
Console.WriteLine(value);
}
Accessors
Note how we created two very similar and innocent looking entities - getter and setter for the property. They are unbound - i.e. not related with any particular instance of the class, and you have to pass the actual instance reference for each operation.
You had to know the field type and name to create them - and that's all.
Now, we will use the bound version of the same getter and setter:
SampleB sampleB = new SampleB(55);
AccessorBuilder.GetFieldValueBoundDelegate<int> instanceValueGetterB =
AccessorBuilder.CreateGetter<int, SampleB>(sampleB, "m_anotherValue");
AccessorBuilder.SetFieldValueBoundDelegate<int> instanceValueSetterB =
AccessorBuilder.CreateSetter<int, SampleB>(sampleB, "m_anotherValue");
List<AccessorBuilder.SetFieldValueBoundDelegate<int>> uniformSet =
new List<AccessorBuilder.SetFieldValueBoundDelegate<int>>();
uniformSet.Add(instanceValueSetterA);
uniformSet.Add(instanceValueSetterB);
List<AccessorBuilder.GetFieldValueBoundDelegate<int>> uniformGet =
new List<AccessorBuilder.GetFieldValueBoundDelegate<int>>();
uniformGet.Add(instanceValueGetterA);
uniformGet.Add(instanceValueGetterB);
uniformSet.ForEach(
delegate(AccessorBuilder.SetFieldValueBoundDelegate<int> item)
{
item(43);
}
);
uniformGet.ForEach(
delegate(AccessorBuilder.GetFieldValueBoundDelegate<int> item)
{
int v = item();
Console.WriteLine("{0}={1}", item.Target.GetType().Name, v);
});
So what do you see here?
We create two int
getters and setters, each working with a different type. We put them in the same list, and access private
values uniformly, just like those classes (SampleA
and SampleB
) are implementing an imaginary IIntFieldOwner
interface. It looks like polymorphic access (it is not exactly the same, because neither class can override/overload this access, but still...).
Note that we are now passing an instance (sampleB
) to the CreateSetter
/CreateGetter
methods, so created delegate
s are bound to specific object instances.
The same functionality can be easily achieved through regular Reflection techniques (with the help of some generic syntax sugar, like here).
But Reflection.Emit
makes things faster (and complicated).
Emit
Emit
is old technology, existing from Framework 1.0, and targeted to .NET assembler wizards, knowing how to generate new code online, but not on the high level language like C# using CodeDom - on .NET assembler level. I don't know how many people actually used it, anyway it is pretty hard to build something complex using Emit
.
In Framework 2.0, they added a more lightweight version of Emit
- dynamic modules, assemblies, etc. It allows you to build and generate classes and methods faster, and use them directly from memory. Moreover, they added a pretty nice feature - the ability to bypass security checks. When Dynamic method is built (without the need to create a module, assembly, etc), you can just pass additional parameters to its constructor - "Type that dynamic method is associated with". This clear specification hides the fact that this dynamic method will have access to all private
members of the "Type
".
So, how do you create a setter, for example?
static private DynamicMethod createSetterImpl<T, O>(string fieldName)
{
if (fieldName == null)
throw new ArgumentNullException("fieldName");
if (fieldName.Length == 0)
throw new ArgumentException("Field name must be non-empty string");
FieldInfo fInfo = typeof(O).GetField(fieldName,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (fInfo == null)
throw new MissingFieldException("Can't obtain field " + fieldName +
" from class " + typeof(O).Name);
if (!typeof(T).IsAssignableFrom(fInfo.FieldType))
throw new InvalidCastException("Field " + fieldName + " of type " +
fInfo.FieldType + " can not be casted to " + typeof(T).FullName);
DynamicMethod setterDef = new
DynamicMethod(typeof(O).Name + "_" + fieldName + "_Setter",
typeof(void),
new Type[] { typeof(O), typeof(T) },
typeof(O));
ILGenerator setterIL = setterDef.GetILGenerator();
setterIL.Emit(OpCodes.Ldarg_0);
setterIL.Emit(OpCodes.Ldarg_1);
setterIL.Emit(OpCodes.Stfld, fInfo);
setterIL.Emit(OpCodes.Ret);
return setterDef;
}
Ok, so we've got some low level beast - DynamicMethod
. How do we create our beautiful object-oriented, type safe, generic delegate
? This can be done very easily as follows:
static public SetFieldValueUnboundDelegate<T,O > CreateSetter<T, O>(string fieldName)
{
SetFieldValueUnboundDelegate<T,O> setter = null;
DynamicMethod setterDef = createSetterImpl<T, O>(fieldName);
setter = (SetFieldValueUnboundDelegate<T,O>)setterDef.CreateDelegate
(typeof(SetFieldValueUnboundDelegate<T,O>));
return setter;
}
And we are back to the line:
AccessorBuilder.SetFieldValueUnboundDelegate<int, SampleA> valueSetter =
AccessorBuilder.CreateSetter<int, SampleA>("m_value");
SampleA sampleA = new SampleA(17);
valueSetter(sampleA, 23);
So, as you can see, almost all work is done by the .NET Framework. We just add some generic - related stuff to make things look prettier (or uglier:), it depends...).
Improvements
AccessorBuilder
can be optimized to cache field information, to prevent FieldInfo
fetch for each request.
Sample Project
It is essentially the same code that you see here, but the full version, that includes all four variations: generation of bound and unbound getters and setters. The solution includes a separate file, AccessorBuilder.cs, where all interesting code resides. An example of usage is in program.cs.
History
- 23rd August, 2007: Initial post