How can I set value into struct field - myStruct.myField with reflection using DynamicMethod? When I call setter(myStruct, 111) value was not set, because MyStruct is value type. Console.WriteLine(myStruct.myField) shows value 3.
How to modify GetDelegate method to set value into myStruct.myField?
public struct MyStruct
{
public int myField;
}
public delegate void SetHandler(object source, object value);
private static SetHandler GetDelegate(Type type, FieldInfo fieldInfo)
{
DynamicMethod dm = new DynamicMethod("setter", typeof(void), new Type[] { typeof(object), typeof(object) }, type, true);
ILGenerator setGenerator = dm.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.DeclareLocal(type);
setGenerator.Emit(OpCodes.Unbox_Any, type);
setGenerator.Emit(OpCodes.Stloc_0);
setGenerator.Emit(OpCodes.Ldloca_S, 0);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
setGenerator.Emit(OpCodes.Stfld, fieldInfo);
setGenerator.Emit(OpCodes.Ldloc, 0);
setGenerator.Emit(OpCodes.Box, type);
setGenerator.Emit(OpCodes.Ret);
return (SetHandler)dm.CreateDelegate(typeof(SetHandler));
}
MyStruct myStruct = new MyStruct();
myStruct.myField = 3;
FieldInfo fi = typeof(MyStruct).GetField("myField", BindingFlags.Public | BindingFlags.Instance);
SetHandler setter = GetDelegate(typeof(MyStruct), fi);
setter(myStruct, 111);
Console.WriteLine(myStruct.myField);
Edit: I made this mistake again - fun fact; unbox-any returns the value; unbox returns the pointer to the data - which allows in-place mutate.
Here's the working IL generation:
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Unbox, type);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
setGenerator.Emit(OpCodes.Stfld, fieldInfo);
setGenerator.Emit(OpCodes.Ret);
But! This is mutating a boxed copy; you would need to unbox afterwards:
object obj = myStruct;
setter(obj, 111);
MyStruct andBackAgain = (MyStruct)obj;
Console.WriteLine(andBackAgain.myField);
Console.WriteLine(myStruct.myField);
To do it in place, you would probably need the method to take a ref MyStruct, or to return a MyStruct. You could return the boxed copy, but that doesn't make it much easier to use. Frankly, it is moot: structs should not generally be mutable.
I think as Servy points out in the comments it's probably better to not have a mutable struct and instead create a copy of the struct with the new value. You can use the SetValueDirect method on the FieldInfo instance if you really want to use reflection to mutate the struct but it uses the undocumented __makeref method to get a TypedReference.
I really wouldn't recommend using this code; it's purely to show that this is possible:
MyStruct myStruct = new MyStruct();
myStruct.myField = 3;
FieldInfo fi = typeof(MyStruct).GetField("myField", BindingFlags.Public | BindingFlags.Instance);
TypedReference reference = __makeref(myStruct);
fi.SetValueDirect(reference, 111);
Console.WriteLine(myStruct.myField); //prints 111
The easiest way to use Reflection to set fields or properties of a structure is to box the structure, pass the boxed structure to SetField or SetProperty, and then unbox the structure once all desired manipulations are complete.
public static class refStructTest
{
struct S1
{
public int x;
public int y { get; set; }
public override string ToString()
{
return String.Format("[{0},{1}]", x, y);
}
}
public static void test()
{
var s = default(S1);
s.x = 2;
s.y = 3;
Object obj = s;
var fld = typeof(S1).GetField("x");
var prop = typeof(S1).GetProperty("y");
fld.SetValue(obj,5);
prop.SetValue(obj,6,null);
s = (S1)obj;
Console.WriteLine("Result={0}", s);
}
}
According to the ECMA documentation, each value type is associated with two kinds of things: a storage location type and a heap object type. The heap object type, like all heap object types, will behave with reference semantics; passing a reference to a heap object to a method like SetValue will thus modify the object to which the reference was passed.
Note for VB users: VB.NET has a really annoying behavior which almost make sense in the Option Strict On dialect, but which exists even in the Option Strict Off dialect: if a variable of compile-time type Object which holds a reference to a boxed structure is assigned to another variable of that same type or passed as a parameter of type Object, VB.NET will store or pass a reference to a copy of the original object. When writing code like the above in VB.NET, one should make obj be of type ValueType rather than Object to prevent such behavior.
Here the code with ref:
public delegate void SetHandler<T>(ref T source, object value) where T : struct;
private static SetHandler<T> GetDelegate<T>(FieldInfo fieldInfo) where T : struct
{
var type = typeof(T);
DynamicMethod dm = new DynamicMethod("setter", typeof(void), new Type[] { type.MakeByRefType(), typeof(object) }, type, true);
ILGenerator setGenerator = dm.GetILGenerator();
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.DeclareLocal(type);
setGenerator.Emit(OpCodes.Ldarg_0);
setGenerator.Emit(OpCodes.Ldnull);
setGenerator.Emit(OpCodes.Stind_Ref);
setGenerator.Emit(OpCodes.Ldarg_1);
setGenerator.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
setGenerator.Emit(OpCodes.Stfld, fieldInfo);
setGenerator.Emit(OpCodes.Ldloc, 0);
setGenerator.Emit(OpCodes.Box, type);
setGenerator.Emit(OpCodes.Ret);
return (SetHandler<T>)dm.CreateDelegate(typeof(SetHandler<>).MakeGenericType(type));
}
static void Main(string[] args)
{
MyStruct myStruct = new MyStruct();
myStruct.myField = 3;
FieldInfo fi = typeof(MyStruct).GetField("myField", BindingFlags.Public | BindingFlags.Instance);
var setter = GetDelegate<MyStruct>(fi);
setter(ref myStruct, 111);
Console.WriteLine(myStruct.myField);
}
To add to other answers, you can actually box inside the delegate, as long as your method also returns the modified struct.
Since my IL-fu is not that great, this is how you would do it with plain reflection:
// the good side is that you can use generic delegates for added type safety
public delegate T SetHandler<T>(T source, object value);
private static SetHandler<T> GetDelegate<T>(FieldInfo fieldInfo)
{
return (s, val) =>
{
object obj = s; // we have to box before calling SetValue
fieldInfo.SetValue(obj, val);
return (T)obj;
};
}
This means you will need to fetch the return value like this:
SetHandler<MyStruct> setter = GetDelegate<MyStruct>(fi);
myStruct = setter(myStruct, 111);
Console.WriteLine(myStruct.myField);
But there's no need to box it before calling the setter.
Alternatively, you can pass the struct using the ref keyword, which would result in:
public delegate void SetHandler<T>(ref T source, object value);
private static SetHandler<T> GetDelegate<T>(FieldInfo fieldInfo)
{
return (ref T s, object val) =>
{
object obj = s;
fieldInfo.SetValue(obj, val);
s = (T)obj;
};
}
SetHandler<MyStruct> setter = GetDelegate<MyStruct>(fi);
setter(ref myStruct, 111); // no need to return anymore
Console.WriteLine(myStruct.myField);
Related
Question is simple: I'm using reflection to get a value. Then if it's a struct, I'm calling a method FooStruct, else FooClass:
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(value);
object obj = type.IsValueType ? val.FooStruct() : val.FooClass();
fieldInfo.SetValue(x, obj);
}
problem is that FooStruct has a constraint:
public static T FooStruct<T>(this T value) where T : struct
{
//...
}
so question is: is it possible to call a method with struct constraint for an object which contains a boxed struct instance without reflection?
I'd happily be proven wrong by another answer, but I don't think this is possible without resorting even more to reflection. See further below for the reason that makes me suspect this. See end of the answer for a reflection-based solution.
Practical suggestion: I would simply drop the constraint on your FooStruct and FooClass methods, and additionally:
either make them non-generic and accept an argument of type object (which is what val is declared as, anyway). There's no advantage to having these methods be generic if they are only ever passed objects;
or cast val from object to T before invoking FooStruct / FooClass.
Why does it seem impossible to do what you're asking? You are trying to convert an expression that is statically typed object (namely val) into something that is statically typed <T> where T : struct or <T> where T : class (in order to call the respective extension method on such a T). That is, you are trying to dynamically introduce a new type variable inside your foreach loop. Unfortunately, the only way to introduce a type variable is to declare it in advance, i.e. as some generic type parameter T in the method's signature; and then it is not the code inside your method that gets to choose what actual type it stands for—it's the calling code that determines T.
Reflection-based solution:
// determine which method ought to be called based on `val`'s run-time type.
// (for C# 6 and later, use the `nameof` operator instead of hard-coding method names)
Type type = val.GetType();
string fooName = type.IsValueType ? "FooStruct" : "FooClass";
// bind to the generic method and supply the type argument for it:
// (I'm assuming that your extension methods are defined in `FooMethodsClass`.)
MethodInfo fooOpen = typeof(FooMethodsClass).GetMethod(fooName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo foo = fooOpen.MakeGenericMethod(new Type[] { type });
// invoke the generic (extension) method with `val` as the `this` argument:
foo.Invoke(null, new object[] { val });
The dynamic variable support will set T appropriately. I use this trick regularly. Try it like this:
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
dynamic val = fieldInfo.GetValue(value);
object obj = type.IsValueType ? Utilities.FooStruct(val) : Utilities.FooClass(val);
fieldInfo.SetValue(x, obj);
}
Apparently you can call the methods with reflection and they work without a problem:
using System;
using System.Reflection;
namespace DemoDynamicT
{
public static class Utilities
{
public static T FooStruct<T>(this T value) where T:struct
{
return default(T);
}
public static T FooClass<T>(this T value) where T : class
{
return default(T);
}
}
public class Program
{
class TestClass
{
public TestStruct StructField;
}
struct TestStruct
{
public int x;
int y;
}
public static void Main()
{
var x = new TestClass();
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(x);
var methodInfo = typeof(Utilities).GetMethod(fieldInfo.FieldType.IsValueType ? "FooStruct" : "FooClass");
var toBeCalled = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
object obj = toBeCalled.Invoke(null, new [] {val});
fieldInfo.SetValue(x, obj);
}
}
}
}
I don't think you can do this directly. You can try workaround like this:
public static class Utilities
{
public static ValueType FooStruct(this ValueType value)
{
//put your code here
return default(ValueType);
}
public static object FooClass(this object value)
{
//put your code here
return null;
}
public static T FooStruct<T>(this T value) where T: struct
{
return (T) FooStruct(value);
}
public static T FooClass<T>(this T value) where T: class
{
return (T) FooClass(value);
}
}
public class Program
{
class TestClass
{
public TestStruct StructField;
}
struct TestStruct
{
int x;
int y;
}
public static void Main()
{
var x = new TestClass();
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(x);
object obj = fieldInfo.FieldType.IsValueType ? ((ValueType)val).FooStruct() : val.FooClass();
fieldInfo.SetValue(x, obj);
}
//Generic call
var structVar = new TestStruct();
structVar.FooStruct();
}
}
I want to know what is fastest way to get value (only for this problem) from an object`s property ?
after some searching I saw a post from #MarkGravell in this site
He wrote this code :
using System;
using System.Reflection;
using System.Reflection.Emit;
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
private int Bar { get; set; }
}
static class Program {
static void Main()
{
var method = new DynamicMethod("cheat", typeof(int),
new[] { typeof(object) }, typeof(Foo), true);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, typeof(Foo));
il.Emit(OpCodes.Callvirt, typeof(Foo).GetProperty("Bar",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
).GetGetMethod(true));
il.Emit(OpCodes.Ret);
var func = (Func<object, int>)method.CreateDelegate(
typeof(Func<object, int>));
var obj = new Foo(123);
Console.WriteLine(func(obj));
}
}
OR
var method = typeof(Foo).GetProperty("Bar",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.GetGetMethod(true);
var func = (Func<Foo, int>)
Delegate.CreateDelegate(typeof(Func<Foo, int>), method);
I changed it to
var pt = propertyInfo.PropertyType; // I dont know what is Type
var method = pt.GetProperty("Bar",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.GetGetMethod(true);
var func = (Func<Foo, object>) // I dont know what is return type so set object !!!
Delegate.CreateDelegate(typeof(Func<Foo, object>), method); // I want get value as object ?!!!
return func(entity).ToString(); // cast return value to string
but I got an exception
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
I dont know what is my property type It can be anything How customize code for this purpose ?
If anyone can help me in better way (fastest way) without property Type restriction please introduce it
The Delegate.CreateDelegate will not work in this case, because you have to cast the resulting delegate to some known type, otherwise all you have is DynamicInvoke which is not better than direct invocation of PropertyInfo (see here explanation by Marc Gravell).
The most generic way I've seen which does not involve lambda expressions (like
Sriram Sakthivel suggested) is shown by Jon Skeet here. Building on his approach and the fact we can get the actual property return type from PropertyInfo, we can invent something custom-tailored for properties invocation.
First, we define an interface:
public interface IPropertyCallAdapter<TThis>
{
object InvokeGet(TThis #this);
//add void InvokeSet(TThis #this, object value) if necessary
}
Then, an implementation of the interface:
public class PropertyCallAdapter<TThis, TResult> : IPropertyCallAdapter<TThis>
{
private readonly Func<TThis, TResult> _getterInvocation;
public PropertyCallAdapter(Func<TThis, TResult> getterInvocation)
{
_getterInvocation = getterInvocation;
}
public object InvokeGet(TThis #this)
{
return _getterInvocation.Invoke(#this);
}
}
The InvokeGet method looks mostly like the one Jon Skeet uses.
Now, to the "magic" part. We define a service which will build and cache an instance of the provider. It looks like this:
public class PropertyCallAdapterProvider<TThis>
{
private static readonly Dictionary<string, IPropertyCallAdapter<TThis>> _instances =
new Dictionary<string,IPropertyCallAdapter<TThis>>();
public static IPropertyCallAdapter<TThis> GetInstance(string forPropertyName)
{
IPropertyCallAdapter<TThis> instance;
if (!_instances.TryGetValue(forPropertyName, out instance))
{
var property = typeof(TThis).GetProperty(
forPropertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo getMethod;
Delegate getterInvocation = null;
if (property != null && (getMethod = property.GetGetMethod(true)) != null)
{
var openGetterType = typeof(Func<,>);
var concreteGetterType = openGetterType
.MakeGenericType(typeof(TThis), property.PropertyType);
getterInvocation =
Delegate.CreateDelegate(concreteGetterType, null, getMethod);
}
else
{
//throw exception or create a default getterInvocation returning null
}
var openAdapterType = typeof(PropertyCallAdapter<,>);
var concreteAdapterType = openAdapterType
.MakeGenericType(typeof(TThis), property.PropertyType);
instance = Activator
.CreateInstance(concreteAdapterType, getterInvocation)
as IPropertyCallAdapter<TThis>;
_instances.Add(forPropertyName, instance);
}
return instance;
}
}
Here, without knowing at compile time the exact TResult type, we create the adapter and cache it for subsequent usage in order to prevent heavy reflection calls in the future.
That's it. You can use it in the following way:
PropertyCallAdapterProvider<Foo>.GetInstance("Bar").InvokeGet(fooInstance)
Also, you can easily extend this for property setters if necessary.
On my machine those are the results for accessing the getter in loop ten million times, using various methods, when the adapter instance is pre-fetched from the provider before entering the loop:
141 milliseconds for direct invocation
244 milliseconds for adapter invocation
1800 milliseconds for reflection invocation
8179 milliseconds for dynamic delegate invocation
I have a value (struct instance) that was cast to object for generic handling. I need to make a copy of the value. I cannot do this explicitly because I just have its Type and don't know what it is in compile time.
By default I get a copy of reference: var copy = objectOfMyStruct;. I thought about making an explicit shallow copy by MemberwiseClone() but I cannot do this because it's protected method and I cannot modify MyStruct.
Convert.ChangeType(objectOfMyStruct, typeOfMyStruct) doesn't help because conversion (actually no conversion) happens inside and it returns Object again.
How could I do this?
EDIT:
I need to make a copy to preserve original value and just deserialized one to pass to OnChangeHandler. Simplified implementation is:
var oldValue = type.GetValue(reference);
var newValue = oldValue; // something better is needed here
Deserialize(type, stream, ref newValue);
OnChange(oldValue, newValue);
type.SetValue(reference, newValue);
Copy is made because only delta (changes) are sent so should be applied to the original value.
EDIT 2:
This implementation works fine for primitive types, so despite int is boxed too I'm copying it instead of copying reference to it. I just don't understand this.
Here is an example of what is needed.
This example, which you can test in LINQPad should make a clone of the struct without casting it back to its unboxed type, so that when it is mutated by a call through the implemented interface, only the original is mutated. The question is thus; how do I write that Clone method?
void Main()
{
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();
// should output different if Clone did its job
clone.Dump();
}
static object Clone(object input)
{
return input;
}
public interface IDummy
{
void Mutate();
}
public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;
public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}
I assume that you not only want to make a copy, but also be able to actually use that copy.
And in order to use it, you need to cast (unbox) it to the appropriate type, which effectively makes a copy. In fact, even putting the value into the box already resulted in a copy.
So, if (for example) you know that these objects are either ints or floats, you could do:
if (obj is int)
{
int i = (int) obj;
// do something with the copy in i
}
else if (obj is float)
{
float f = (float) obj;
// do something with the copy in f
}
If you have a large number of types to evaluate, you can use a switch statement or even a Dictionary<Type,Action<object>>.
If you need to deal with types that you don't know about at compile time (some type added dynamically thorugh some kind of plugin mechanism) than this won't be possible, but then again, it would also not be possible to do anything with the object (unless through an interface).
UPDATE:
Now that you changed your question, here's a better answer: you do no need to make a copy, it has been made for you by boxing the struct.
Example:
int i = 42;
// make a copy on the heap
object obj = i;
// modify the original
i = i + 1;
// copy is not modified
Debug.Assert((int)obj == 42);
Obviously, I'm using int here for convenience, but it is true for every struct. If the struct implements an interface, you can cast the object to that interface (that won't make a second copy) and use it. It will not modify the orginal value, because it is operating on the copy in the box.
UPDATE 2:
Just to be very explicit: this works for every struct. For example:
interface IIncrementor
{
void Increment();
}
struct MyStruct : IIncrementor
{
public int i;
public void Increment()
{
this.i = this.i + 1;
}
public override string ToString()
{
return i.ToString();
}
}
// in some method:
MyStruct ms = new MyStruct();
ms.i = 42;
Console.Writeline(ms); // 42
object obj = ms;
IIncrementable ii = (IIncrementable) obj;
ii.Increment();
Console.Writeline(ms); // still 42
Console.Writeline(ii); // 43
One more UPDATE:
instead of
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
write
Dummy original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = original;
and you'll be fine.
Thanks for the LINQPad example, it greatly clarified your question and it gave me a starting point for coming up with a solution.
This is a very brute-force solution, but it might serve your purpose, until somebody comes up with a more elegant answer:
static object Clone(object input)
{
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(input));
try
{
Marshal.StructureToPtr(input, p, false);
return Marshal.PtrToStructure(p, input.GetType());
}
finally
{
Marshal.FreeHGlobal(p);
}
}
This is how it works:
It allocates unmanaged memory large enough to hold your struct.
StructureToPtr unboxes your input and copies it into unmanaged memory:
If structure is a value type, it can be boxed or unboxed. If it is boxed, it is unboxed before copying.
PtrToStructure creates a new structure, boxes it and returns it:
You can pass a value type to this overload method. In this case, the returned object is a boxed instance.
The unmanaged memory is freed.
Here's another answer:
static object Clone(object input) =>
typeof(object)
.GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance)
.Invoke(input, null);
It uses the Object.MemberwiseClone method. This method is protected, which is why I have to call it via reflection.
This approach works fine with enums, and with structs that have [StructLayout(LayoutKind.Auto)].
If the list of types to handle this cloning for is controlled, that is, you know which types you need to handle this for, then I would simply create a dictionary that contains functions that knows how to handle each particular type.
Here's a LINQPad example:
void Main()
{
_CloneMapping[typeof(Dummy)] = (object obj) =>
{
Dummy d = (Dummy)obj;
return new Dummy { Field = d.Field, Property = d.Property };
};
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);
((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();
// should output different if Clone did its job
clone.Dump();
}
static readonly Dictionary<Type, Func<object, object>> _CloneMapping = new Dictionary<Type, Func<object, object>>();
static object Clone(object input)
{
if (input == null)
return null;
var cloneable = input as ICloneable;
if (cloneable != null)
return cloneable.Clone();
Func<object, object> cloner;
if (_CloneMapping.TryGetValue(input.GetType(), out cloner))
return cloner(input);
throw new NotSupportedException();
}
public interface IDummy
{
void Mutate();
}
public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;
public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}
This will output:
I need to find out a size of a generic structure (I can not do it like sizeof(T) or using Marshal.SizeOf(...) 0> gives me an error)
So I wrote:
public static class HelperMethods
{
static HelperMethods()
{
SizeOfType = createSizeOfFunc();
}
public static int SizeOf<T>()
{
return SizeOfType(typeof(T));
}
public static readonly Func<Type, int> SizeOfType = null;
private static Func<Type, int> createSizeOfFunc()
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { typeof(Type) });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Sizeof); //needs to be il.Emit(OpCodes.Sizeof, typeof(something))
il.Emit(OpCodes.Ret);
var func = (Func<Type, int>)dm.CreateDelegate(typeof(Func<Type, int>));
return func;
}
}
A diffuclty is that il.Emit(OpCodes.Sizeof) needs an argument which I can not pass it during the method (SizeOfType) creation. How can I pass a parameter which is on stack to il.Emit(OpCodes.Sizeof) using IL ? (or a different solution but I want to cache a function (delegate) not a result what is proposed in the 2nd answer)
Taking the above thinking one step further, I arrived at:
public static class TypeSize<T>
{
public readonly static int Size;
static TypeSize()
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Sizeof, typeof(T));
il.Emit(OpCodes.Ret);
Size = (int)dm.Invoke(null, null);
}
}
...which I believe is the most efficient solution to the problem.
Computing size is something that is fraught with problems because you need to know what is meaningful in the context you are using it. I'd assume there is a good reason for Marshal.SizeOf to throw when the argument is a generic struct, but I don't know what it is.
With that caveat, this code seems to work and gives similar results to Marshal.SizeOf for non-generic structs. It generates a new dynamic method that gets the size via the sizeof IL opcode for the type. It then caches the result (since generating a dynamic method is some what expensive) for future use.
public class A { int x,y,z; }
public struct B { int x,y,z,w,a,b; }
public struct C<T> { Guid g; T b,c,d,e,f; }
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(IntPtr.Size); // on x86 == 4
Console.WriteLine(SizeHelper.SizeOf(typeof(C<double>))); // prints 56 on x86
Console.WriteLine(SizeHelper.SizeOf(typeof(C<int>))); // prints 36 on x86
}
}
static class SizeHelper
{
private static Dictionary<Type, int> sizes = new Dictionary<Type, int>();
public static int SizeOf(Type type)
{
int size;
if (sizes.TryGetValue(type, out size))
{
return size;
}
size = SizeOfType(type);
sizes.Add(type, size);
return size;
}
private static int SizeOfType(Type type)
{
var dm = new DynamicMethod("SizeOfType", typeof(int), new Type[] { });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Sizeof, type);
il.Emit(OpCodes.Ret);
return (int)dm.Invoke(null, null);
}
}
Edit
As far as I can tell there is no way to make non-generic delegate that you can cache. The SizeOf opcode requires a metadata token. It does not take a value from the evaluation stack.
Actually the code below works as well. I'm not sure why Marshal.SizeOf(Type) throws an argument exception when the type is generic structure but Marshal.SizeOf(Object) does not.
public static int SizeOf<T>() where T : struct
{
return Marshal.SizeOf(default(T));
}
It would appear that your aim is to resolve the argument Type from your functions return type Func<Type, int> at compile time. This information is not known at compile time and there is no apparent way to resolve this information using reflection at runtime.
I do not see what benefit returning the the dynamic method serves instead of invoking the dynamic method and returning the result immediately. Given that you have not given any context I would propose the obvious solution, return the value immediately. If your concerns lie with performance then simply cache the results in a dictionary.
public static class GlobalExtensions
{
public static int SizeOf<T>()
{
return SizeOf(typeof (T));
}
public static int SizeOf(this Type type)
{
var dynamicMethod = new DynamicMethod("SizeOf", typeof(int), Type.EmptyTypes);
var generator = dynamicMethod.GetILGenerator();
generator.Emit(OpCodes.Sizeof, type);
generator.Emit(OpCodes.Ret);
var function = (Func<int>) dynamicMethod.CreateDelegate(typeof(Func<int>));
return function();
}
}
Using an extension method leverages some nice syntax. You can now proceed to obtain the size of a generic structure or class using the following code:
var size = TypeExtensions.SizeOf<Example<int>>();
//alternative syntax...
size = typeof (Example<int>).SizeOf();
Now there is possibility for the unmanaged types in unsafe context to do this, if that is sufficient.
private unsafe int MySizeOf<T>() where T : unmanaged
{
return sizeof(T);
}
No doubt elements of this question have been asked before, but I'm having trouble finding an answer. (Disclaimer: this is related, but separate from a recent question I asked).
I have a method like this:
public static void Method<T>(MethodInfo m, T value)
{
Type memberType = m.GetValueType();
if (memberType.IsAssignableFrom(typeof(List<T>))
{
object memberValue = Activator.CreateInstance(memberType);
((List<T>)memberValue).Add(value);
}
}
This works fine when I call it like this:
string s = "blah";
Method(memberInfo, s);
However, I need to call this method using a generic type, so I'm calling it like this:
Type valueType = someType;
object passValue = someMethod.MakeGenericMethod(new Type[] { valueType }).Invoke(this, new object[] { });
/* Call my original method */
Method(memberInfo, passValue );
Now, intellisense knows that 'value' in Method<T> is whatever type valueType is (say 'FooObject'). But 'T' is object, which means that a List<FooObject> is not assignable from a List<T> (i.e. a List<object>).
I've tried using Convert.ChangeType on the variable ('passValue') beforehand but that wasn't any more useful.
As there is no way to cast a variable to the Type of a type variable, how do I get around this?
Is the best solution to somehow not rely on IsAssignableFrom and do a looser type check of whether this will work? The problem with this is that I'm not sure I'll be able to cast the memberValue properly unless 'T' is truly the element type of memberValue.
This should give you a callable method (I'll test it in a little while). The boxing/unboxing it incurs is much faster than the security checks required for the Reflection API invocation (which happens to also require boxing).
private static Action<MethodInfo, object> BuildAccessor(Type valueType)
{
MethodInfo genericMethod = null; // <-- fill this in
MethodInfo method = genericMethod.MakeGenericMethod(new Type[] { valueType });
ParameterExpression methodInfo = Expression.Parameter(typeof(MethodInfo), "methodInfo");
ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
Expression<Action<MethodInfo, object>> expr =
Expression.Lambda<Action<MethodInfo, object>>(
Expression.Call(method, methodInfo, Expression.Convert(obj, valueType)),
methodInfo,
obj);
return expr.Compile();
}
You're in luck. I actually had to do something very similar a few weeks ago.
For a detailed explanation see the above blog post, but basically the general idea is to reflect the type and manually invoke the method with an explicit set of parameters.
typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param });
It's not very type safe, but it does exactly what you're looking for.
class Program
{
static void Main(string[] args)
{
object str = "Hello World";
object num = 5;
object obj = new object();
Console.WriteLine("var\tvalue\t\tFoo() Type\tCallFoo() Type");
Console.WriteLine("-------------------------------------------------------");
Console.WriteLine("{0}\t{1}\t{2}\t{3}", "str", str, MyClass.Foo(str), MyClass.CallFoo(str));
Console.WriteLine("{0}\t{1}\t\t{2}\t{3}", "num", num, MyClass.Foo(num), MyClass.CallFoo(num));
Console.WriteLine("{0}\t{1}\t{2}\t{3}", "obj", obj, MyClass.Foo(obj), MyClass.CallFoo(obj));
}
}
class MyClass
{
public static Type Foo<T>(T param)
{
return typeof(T);
}
public static Type CallFoo(object param)
{
return (Type)typeof(MyClass).GetMethod("Foo").MakeGenericMethod(new[] { param.GetType() }).Invoke(null, new[] { param });
}
}
Output
var value Foo() Type CallFoo() Type
-------------------------------------------------------
str Hello World System.Object System.String
num 5 System.Object System.Int32
obj System.Object System.Object System.Object