Generating IL for Nullable<T> serialization? - c#

I'm writing my own serializer that emits IL to generate the [de]serialization codes.
For nullables, I thought I could generate the following (take int? as an ex) (assuming we already generated methods to [de]serialize int):
public static void Serialize(Stream stream, int? value, object context)
{
Serialize(stream, (int)value, context);
}
public static void Deseiralize(Stream stream, out int? value, object context)
{
int tmp;
Deserialize(stream, out tmp, context);
value = tmp;
}
Here's how I generate that:
public override void GenSerializationCode(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
var serialize = GetSerializeCall(underlyingType);
// Serialize(stream, (UnderlyingType)value, context);
emit.ldarg_0()
.ldarg_1()
.unbox_any(underlyingType)
.ldarg_2()
.call(serialize)
.ret();
}
public override void GenDeserializationCode(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
var deserialize = GetDeserializeCall(underlyingType);
// UnderlyingType tmp; Deserialize(stream, out tmp, context);
var tmp = emit.declocal(underlyingType);
emit.ldarg_0()
.ldloca_s(tmp)
.ldarg_2()
.call(deserialize);
// value = tmp;
emit.ldarg_1()
.ldloc_s(tmp)
.stind_ref()
.ret();
}
I also generate an assembly for debugging. I load it up in ILSpy and the C# code looks exactly like what I had in mind. But peverify had something else to say...
I thought about it for a minute, then realized that Nullable<T> is a struct, so I should use Ldarga instead of Ldarg so I changed my ldarg_1() to ldarga(1)
Now peverify gives:
[IL]: Error: [C:\Users\vexe\Desktop\MyExtensionsAndHelpers\Solution\CustomSerializer\bin\Release\SerTest.dll : FastSerializer::Serialize][offset 0x00000007][found address of value 'System.Nullable`1[System.Int32]'] Expected an ObjRef on the stack.
I thought it's something to do with Nullable<T> conversion operators so I tried the Value property:
var underlyingType = Nullable.GetUnderlyingType(type);
var serialize = GetSerializeCall(underlyingType);
var getValue = type.GetProperty("Value").GetGetMethod();
// Serialize(stream, value.get_Value(), context);
emit.ldarg_0()
.ldarga(1)
.call(getValue)
.ldarg_2()
.call(serialize)
.ret();
peverify is happy about this!
The question is, why didn't the explicit operator from T to Nullable<T> kick in previously when casting the nullable to its underlying type?
Also, I wasn't able to get rid of the error in Deserialize even when using Ldarga instead of Ldarg when doing value = tmp;- I guess I could try what the implicit conversion is doing. i.e. value = new Nullable<int>(tmp); but I would like to find out what I did wrong.
Note: 'emit' is just a helper I use to generate IL. It uses an ILGenerator internally and returns itself after each operation so I can chain together calls.
EDIT: here's the final code that worked, with notes and all.
// Note:
// 1- IL doesn't know anything about implicit/explicit operators
// so we can't make use of the T to Nullable<T> nor Nullable<T> to T operators
// that's why we have to use the Value property when serializing and the ctor when deserializing
// 2- Nullable<T> is a struct
// so we use ldarga when calling the property getter when serializing (the property getter is an instance method, so the first argument is always the 'this', but since we're dealing with structs we have to pass 'this' by ref hence ldarga)
// then use stobj opcode when constructing an instance when deserializing
public override void GenSerializationCode(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
var serialize = ctx.GetSerializeCall(underlyingType);
var getValue = type.GetProperty("Value").GetGetMethod();
// Serialize(stream, value.get_Value(), ctx);
emit.ldarg_0()
.ldarga(1)
.call(getValue)
.ldarg_2()
.call(serialize)
.ret();
}
public override void GenDeserializationCode(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
var deserialize = ctx.GetDeserializeCall(underlyingType);
// UnderlyingType tmp; Deserialize(stream, out tmp, ctx);
var tmp = emit.declocal(underlyingType);
emit.ldarg_0()
.ldloca_s(tmp)
.ldarg_2()
.call(deserialize);
// value = new Nullable<UnderlyingType>(tmp);
var ctor = type.GetConstructor(new Type[] { underlyingType });
emit.ldarg_1()
.ldloc_s(tmp)
.newobj(ctor)
.stobj(type)
.ret();
}
}

Explicit and implicit conversions are a purely C# concept.
IL does not have any special awareness of nullable types (except for boxing them into Objects); you need to explicitly use .Value or call the ctor.
For examples, look at the IL generated by the C# compiler.

Operators is only for the C# and VB.NET compilers. IL and IL generations knows nothing about it.

Related

In c#, how do I know what subclass an object is when stored as the parent? [duplicate]

I've seen many people use the following code:
Type t = obj1.GetType();
if (t == typeof(int))
// Some code here
But I know you could also do this:
if (obj1.GetType() == typeof(int))
// Some code here
Or this:
if (obj1 is int)
// Some code here
Personally, I feel the last one is the cleanest, but is there something I'm missing? Which one is the best to use, or is it personal preference?
All are different.
typeof takes a type name (which you specify at compile time).
GetType gets the runtime type of an instance.
is returns true if an instance is in the inheritance tree.
Example
class Animal { }
class Dog : Animal { }
void PrintTypes(Animal a) {
Console.WriteLine(a.GetType() == typeof(Animal)); // false
Console.WriteLine(a is Animal); // true
Console.WriteLine(a.GetType() == typeof(Dog)); // true
Console.WriteLine(a is Dog); // true
}
Dog spot = new Dog();
PrintTypes(spot);
What about typeof(T)? Is it also resolved at compile time?
Yes. T is always what the type of the expression is. Remember, a generic method is basically a whole bunch of methods with the appropriate type. Example:
string Foo<T>(T parameter) { return typeof(T).Name; }
Animal probably_a_dog = new Dog();
Dog definitely_a_dog = new Dog();
Foo(probably_a_dog); // this calls Foo<Animal> and returns "Animal"
Foo<Animal>(probably_a_dog); // this is exactly the same as above
Foo<Dog>(probably_a_dog); // !!! This will not compile. The parameter expects a Dog, you cannot pass in an Animal.
Foo(definitely_a_dog); // this calls Foo<Dog> and returns "Dog"
Foo<Dog>(definitely_a_dog); // this is exactly the same as above.
Foo<Animal>(definitely_a_dog); // this calls Foo<Animal> and returns "Animal".
Foo((Animal)definitely_a_dog); // this does the same as above, returns "Animal"
Use typeof when you want to get the type at compilation time. Use GetType when you want to get the type at execution time. There are rarely any cases to use is as it does a cast and, in most cases, you end up casting the variable anyway.
There is a fourth option that you haven't considered (especially if you are going to cast an object to the type you find as well); that is to use as.
Foo foo = obj as Foo;
if (foo != null)
// your code here
This only uses one cast whereas this approach:
if (obj is Foo)
Foo foo = (Foo)obj;
requires two.
Update (Jan 2020):
As of C# 7+, you can now cast inline, so the 'is' approach can now be done in one cast as well.
Example:
if(obj is Foo newLocalFoo)
{
// For example, you can now reference 'newLocalFoo' in this local scope
Console.WriteLine(newLocalFoo);
}
1.
Type t = typeof(obj1);
if (t == typeof(int))
This is illegal, because typeof only works on types, not on variables. I assume obj1 is a variable. So, in this way typeof is static, and does its work at compile time instead of runtime.
2.
if (obj1.GetType() == typeof(int))
This is true if obj1 is exactly of type int. If obj1 derives from int, the if condition will be false.
3.
if (obj1 is int)
This is true if obj1 is an int, or if it derives from a class called int, or if it implements an interface called int.
Type t = typeof(obj1);
if (t == typeof(int))
// Some code here
This is an error. The typeof operator in C# can only take type names, not objects.
if (obj1.GetType() == typeof(int))
// Some code here
This will work, but maybe not as you would expect. For value types, as you've shown here, it's acceptable, but for reference types, it would only return true if the type was the exact same type, not something else in the inheritance hierarchy. For instance:
class Animal{}
class Dog : Animal{}
static void Foo(){
object o = new Dog();
if(o.GetType() == typeof(Animal))
Console.WriteLine("o is an animal");
Console.WriteLine("o is something else");
}
This would print "o is something else", because the type of o is Dog, not Animal. You can make this work, however, if you use the IsAssignableFrom method of the Type class.
if(typeof(Animal).IsAssignableFrom(o.GetType())) // note use of tested type
Console.WriteLine("o is an animal");
This technique still leaves a major problem, though. If your variable is null, the call to GetType() will throw a NullReferenceException. So to make it work correctly, you'd do:
if(o != null && typeof(Animal).IsAssignableFrom(o.GetType()))
Console.WriteLine("o is an animal");
With this, you have equivalent behavior of the is keyword. Hence, if this is the behavior you want, you should use the is keyword, which is more readable and more efficient.
if(o is Animal)
Console.WriteLine("o is an animal");
In most cases, though, the is keyword still isn't what you really want, because it's usually not enough just to know that an object is of a certain type. Usually, you want to actually use that object as an instance of that type, which requires casting it too. And so you may find yourself writing code like this:
if(o is Animal)
((Animal)o).Speak();
But that makes the CLR check the object's type up to two times. It will check it once to satisfy the is operator, and if o is indeed an Animal, we make it check again to validate the cast.
It's more efficient to do this instead:
Animal a = o as Animal;
if(a != null)
a.Speak();
The as operator is a cast that won't throw an exception if it fails, instead returning null. This way, the CLR checks the object's type just once, and after that, we just need to do a null check, which is more efficient.
But beware: many people fall into a trap with as. Because it doesn't throw exceptions, some people think of it as a "safe" cast, and they use it exclusively, shunning regular casts. This leads to errors like this:
(o as Animal).Speak();
In this case, the developer is clearly assuming that o will always be an Animal, and as long as their assumption is correct, everything works fine. But if they're wrong, then what they end up with here is a NullReferenceException. With a regular cast, they would have gotten an InvalidCastException instead, which would have more correctly identified the problem.
Sometimes, this bug can be hard to find:
class Foo{
readonly Animal animal;
public Foo(object o){
animal = o as Animal;
}
public void Interact(){
animal.Speak();
}
}
This is another case where the developer is clearly expecting o to be an Animal every time, but this isn't obvious in the constructor, where the as cast is used. It's not obvious until you get to the Interact method, where the animal field is expected to be positively assigned. In this case, not only do you end up with a misleading exception, but it isn't thrown until potentially much later than when the actual error occurred.
In summary:
If you only need to know whether or not an object is of some type, use is.
If you need to treat an object as an instance of a certain type, but you don't know for sure that the object will be of that type, use as and check for null.
If you need to treat an object as an instance of a certain type, and the object is supposed to be of that type, use a regular cast.
If you're using C# 7, then it is time for an update to Andrew Hare's great answer. Pattern matching has introduced a nice shortcut that gives us a typed variable within the context of the if statement, without requiring a separate declaration/cast and check:
if (obj1 is int integerValue)
{
integerValue++;
}
This looks pretty underwhelming for a single cast like this, but really shines when you have many possible types coming into your routine. The below is the old way to avoid casting twice:
Button button = obj1 as Button;
if (button != null)
{
// do stuff...
return;
}
TextBox text = obj1 as TextBox;
if (text != null)
{
// do stuff...
return;
}
Label label = obj1 as Label;
if (label != null)
{
// do stuff...
return;
}
// ... and so on
Working around shrinking this code as much as possible, as well as avoiding duplicate casts of the same object has always bothered me. The above is nicely compressed with pattern matching to the following:
switch (obj1)
{
case Button button:
// do stuff...
break;
case TextBox text:
// do stuff...
break;
case Label label:
// do stuff...
break;
// and so on...
}
EDIT: Updated the longer new method to use a switch as per Palec's comment.
I had a Type-property to compare to and could not use is (like my_type is _BaseTypetoLookFor), but I could use these:
base_type.IsInstanceOfType(derived_object);
base_type.IsAssignableFrom(derived_type);
derived_type.IsSubClassOf(base_type);
Notice that IsInstanceOfType and IsAssignableFrom return true when comparing the same types, where IsSubClassOf will return false. And IsSubclassOf does not work on interfaces, where the other two do. (See also this question and answer.)
public class Animal {}
public interface ITrainable {}
public class Dog : Animal, ITrainable{}
Animal dog = new Dog();
typeof(Animal).IsInstanceOfType(dog); // true
typeof(Dog).IsInstanceOfType(dog); // true
typeof(ITrainable).IsInstanceOfType(dog); // true
typeof(Animal).IsAssignableFrom(dog.GetType()); // true
typeof(Dog).IsAssignableFrom(dog.GetType()); // true
typeof(ITrainable).IsAssignableFrom(dog.GetType()); // true
dog.GetType().IsSubclassOf(typeof(Animal)); // true
dog.GetType().IsSubclassOf(typeof(Dog)); // false
dog.GetType().IsSubclassOf(typeof(ITrainable)); // false
I prefer is
That said, if you're using is, you're likely not using inheritance properly.
Assume that Person : Entity, and that Animal : Entity. Feed is a virtual method in Entity (to make Neil happy)
class Person
{
// A Person should be able to Feed
// another Entity, but they way he feeds
// each is different
public override void Feed( Entity e )
{
if( e is Person )
{
// feed me
}
else if( e is Animal )
{
// ruff
}
}
}
Rather
class Person
{
public override void Feed( Person p )
{
// feed the person
}
public override void Feed( Animal a )
{
// feed the animal
}
}
I believe the last one also looks at inheritance (e.g. Dog is Animal == true), which is better in most cases.
It depends on what I'm doing. If I need a bool value (say, to determine if I'll cast to an int), I'll use is. If I actually need the type for some reason (say, to pass to some other method) I'll use GetType().
The last one is cleaner, more obvious, and also checks for subtypes. The others do not check for polymorphism.
Used to obtain the System.Type object for a type. A typeof expression takes the following form:
System.Type type = typeof(int);
Example:
public class ExampleClass
{
public int sampleMember;
public void SampleMethod() {}
static void Main()
{
Type t = typeof(ExampleClass);
// Alternatively, you could use
// ExampleClass obj = new ExampleClass();
// Type t = obj.GetType();
Console.WriteLine("Methods:");
System.Reflection.MethodInfo[] methodInfo = t.GetMethods();
foreach (System.Reflection.MethodInfo mInfo in methodInfo)
Console.WriteLine(mInfo.ToString());
Console.WriteLine("Members:");
System.Reflection.MemberInfo[] memberInfo = t.GetMembers();
foreach (System.Reflection.MemberInfo mInfo in memberInfo)
Console.WriteLine(mInfo.ToString());
}
}
/*
Output:
Methods:
Void SampleMethod()
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Members:
Void SampleMethod()
System.String ToString()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
Void .ctor()
Int32 sampleMember
*/
This sample uses the GetType method to determine the type that is used to contain the result of a numeric calculation. This depends on the storage requirements of the resulting number.
class GetTypeTest
{
static void Main()
{
int radius = 3;
Console.WriteLine("Area = {0}", radius * radius * Math.PI);
Console.WriteLine("The type is {0}",
(radius * radius * Math.PI).GetType()
);
}
}
/*
Output:
Area = 28.2743338823081
The type is System.Double
*/
I found checking if the type of something is equal to something is done by the following:
variableName.GetType() == typeof(int)
if (c is UserControl) c.Enabled = enable;
You can use "typeof()" operator in C# but you need to call the namespace using System.IO; You must use "is" keyword if you wish to check for a type.
Performance test typeof() vs GetType():
using System;
namespace ConsoleApplication1
{
class Program
{
enum TestEnum { E1, E2, E3 }
static void Main(string[] args)
{
{
var start = DateTime.UtcNow;
for (var i = 0; i < 1000000000; i++)
Test1(TestEnum.E2);
Console.WriteLine(DateTime.UtcNow - start);
}
{
var start = DateTime.UtcNow;
for (var i = 0; i < 1000000000; i++)
Test2(TestEnum.E2);
Console.WriteLine(DateTime.UtcNow - start);
}
Console.ReadLine();
}
static Type Test1<T>(T value) => typeof(T);
static Type Test2(object value) => value.GetType();
}
}
Results in debug mode:
00:00:08.4096636
00:00:10.8570657
Results in release mode:
00:00:02.3799048
00:00:07.1797128

How to access base-class member using a generic-type constrained to interface? [duplicate]

This is likely a a novice question, but google surprisingly did not provide an answer.
I have this rather artificial method
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
T newT1 = "some text";
T newT2 = (string)t;
}
return t;
}
Coming from a C++ background I have expected this to work. However, it fails to compile with "Cannot implicitly convert type 'T' to string" and "Cannot convert type 'T' to string" for both of the above assignments.
I am either doing something conceptually wrong or just have the wrong syntax. Please help me sort this one out.
Thank you!
Even though it's inside of an if block, the compiler doesn't know that T is string.
Therefore, it doesn't let you cast. (For the same reason that you cannot cast DateTime to string)
You need to cast to object, (which any T can cast to), and from there to string (since object can be cast to string).
For example:
T newT1 = (T)(object)"some text";
string newT2 = (string)(object)t;
Both lines have the same problem
T newT1 = "some text";
T newT2 = (string)t;
The compiler doesn't know that T is a string and so has no way of knowing how to assign that.
But since you checked you can just force it with
T newT1 = "some text" as T;
T newT2 = t;
you don't need to cast the t since it's already a string, also need to add the constraint
where T : class
I know similar code that the OP posted in this question from generic parsers. From a performance perspective, you should use Unsafe.As<TFrom, TResult>(ref TFrom source), which can be found in the System.Runtime.CompilerServices.Unsafe NuGet package. It avoids boxing for value types in these scenarios. I also think that Unsafe.As results in less machine code produced by the JIT than casting twice (using (TResult) (object) actualString), but I haven't checked that out.
public TResult ParseSomething<TResult>(ParseContext context)
{
if (typeof(TResult) == typeof(string))
{
var token = context.ParseNextToken();
string parsedString = token.ParseToDotnetString();
return Unsafe.As<string, TResult>(ref parsedString);
}
else if (typeof(TResult) == typeof(int))
{
var token = context.ParseNextToken();
int parsedInt32 = token.ParseToDotnetInt32();
// This will not box which might be critical to performance
return Unsafe.As<int, TResult>(ref parsedInt32);
}
// other cases omitted for brevity's sake
}
Unsafe.As will be replaced by the JIT with efficient machine code instructions, as you can see in the official CoreFX repo:
If you're checking for explicit types, why are you declaring those variables as T's?
T HowToCast<T>(T t)
{
if (typeof(T) == typeof(string))
{
var newT1 = "some text";
var newT2 = t; //this builds but I'm not sure what it does under the hood.
var newT3 = t.ToString(); //for sure the string you want.
}
return t;
}
You will also get this error if you have a generic declaration for both your class and your method. For example the code shown below gives this compile error.
public class Foo <T> {
T var;
public <T> void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
This code does compile (note T removed from method declaration):
public class Foo <T> {
T var;
public void doSomething(Class <T> cls) throws InstantiationException, IllegalAccessException {
this.var = cls.newInstance();
}
}
Change this line:
if (typeof(T) == typeof(string))
For this line:
if (t.GetType() == typeof(string))

How to return a specific type of object from List<object>

I have a List<object> which is a collection of various type of objects.
I am writing a helper method which will return a specific type of object. The helper method will accept type name as string parameter.
Note: I am using 3.5 framework.
If you need to use a string as parameter you can't rely on OfType<T>() extension method. Fortunately it's easy to emulate:
public IEnumerable<object> OfType(this List<object> list, string typeName)
{
return list.Where(x => x != null && x.GetType().Name == typeName);
}
As pointed out by #ChrisSinclair in the comment this solution does not manage conversions, casts and inheritance/interfaces. Casts (because of user defined conversion operators) and conversions (because of TypeConverters and the IConvertible interface) are little bit more tricky. For simple (implicit) casts (like with inheritance and interfaces) you can use this:
public IEnumerable<object> OfType(this List<object> list, string typeName)
{
Type type = Type.GetType(typeName);
return list.Where(x => x != null && type.IsAssignableFrom(x.GetType()));
}
How to perform conversions (even with CUSTOM CONVERSION OPERATORS) at run-time
I found I needed something like the code I posted in this answer but I had to extend it a little bit, here a better implementation that takes care of custom casts and conversions.
Put everything inside a CastExtensions class (or update code if you don't) then declare this small enum for its options:
[Flags]
public enum CastOptions
{
None = 0,
ExcludeNulls = 1,
UseConversions = 2
}
The problem is that C# in general is a statically typed language, it means that almost everything (about types) must be known at compile time (then to perform a cast you have to know type your want to cast to at compile time). This function handles simple cases (like derivation) and more complex ones (interfaces, custom conversion operators - casts - and conversions - when required).
public static IEnumerable<object> OfType(this List<object> list,
string typeName, CastOptions options)
{
Type type = Type.GetType(typeName);
foreach (var obj in list)
{
if (Object.ReferenceEquals(obj, null))
{
if (options.HasFlag(CastOptions.ExcludeNulls))
continue;
yield return obj;
}
var objectType = obj.GetType();
// Derived type?
if (type.IsAssignableFrom(objectType))
yield return obj;
// Should we try to convert?
if (!options.HasFlag(CastOptions.UseConversions))
continue;
// Castable?
object convertedValue = null;
try
{
var method = typeof(CastExtensions)
.GetMethod("Cast", BindingFlags.Static|BindingFlags.NonPublic)
.MakeGenericMethod(type);
convertedValue = method.Invoke(null, new object[] { obj });
}
catch (InvalidCastException)
{
// No implicit/explicit conversion operators
}
if (convertedValue != null)
yield return convertedValue;
// Convertible?
if (options.HasFlag(CastOptions.UseConversions))
{
try
{
IConvertible convertible = obj as IConvertible;
if (convertible != null)
convertible.ToType(type, CultureInfo.CurrentCulture);
}
catch (Exception)
{
// Exact exception depends on the source object type
}
}
}
}
Note that conversion may be or not equivalent to a cast, actually it depends on
the implementation and the exact types involved in the operation (that's why you
can enable or disable this feature through options).
This is a small helper function needed for cast at run-time:
private static T Cast<T>(object obj)
{
return (T)obj;
}
We may emit this code at run-time (I suppose even using expressions but I didn't try) but a small helper method will generate exactly the code we need (conversion from an object to a generic known at run-time type). Note that this cast function doesn't work as expected for value types, for example:
int a = 1;
float a = Cast<float>(a); // Run-time error
This is because (object)1 cannot be converted to anything else than int (this is true for all boxed value types). If you're using C# 4.0 you should change object for parameter obj to dynamic and everything will work as expected (for all types).
Maybe something like that :
var ofTypeTypeA = myList.OfType<TypeA>();
A clean way is to force the user to specify the type as type to avoid loose strings in your application.
Then you could use generics and just use the type you are interested in. That would also allow the caller to skip the cast when using the IEnumerable later.
So instead of this:
List<object> newList = GetOfType(myList, "SomeObject");
// CAST!!
SomeObject someObject = newList[0] as SomeObject;
if (someObject != null)
// use object
you would just do:
IEnumerable<SomeObject> newList = myList.OfType<SomeObject>();
foreach (SomeObject someObject in newList){
// no cast neccessary
This makes it unsensitive in the future if you should rename the class SomeObject (because refactoring tools would pick up on the class name instead of the string)
You can use Enumerable.OfType
var input = new List<object>();
input.Add(1);
input.Add("foo");
var bar = input.OfType<string>();
I guess you need to cast a single object extracted from the list to a strongly-typed object. And not to cast all the list to it. Otherwise use List<MyType>.
So I would go with this: How to cast to a type in C#.
You could use the is operator (or pass the type and check for that also using is). Here is an example of using the is operator:
foreach (var ctl in ControlsList)
{
if (ctl is CheckBox)
//Do this
else if (ctl is TextBox)
//DoThis
}
And by passing the type as string in the parameter, you could do something similar to get the type to test against:
Type t = System.Type.GetType("System.Int32");

Why can I not bind a DynamicMethod to a struct instance?

DynamicMethods allow you to specify a target instance for the delegate you create. However, it appears that this does not work when you use a struct type. It fails with an exception telling me it cannot bind to this method. Is the error because my IL does not unbox the target instance?
If I change A here to a class it works without issue. What am I doing wrong?
(Also please do not suggest calling Delegate.CreateDelegate to bind to the GetType method with a target instance)
Here is a sample repro:
struct A { }
... //then some where in code::
Func<Type> f = CodeGen.CreateDelegate<Func<Type>>(il=>
il.ldarga_s(0)
.constrained(typeof(A))
.callvirt(typeof(object).GetMethod("GetType"))
.ret(),
name:"Constrained",
target:new A()
);
Note: I'm using the Emitted library for the fluent interface for IL. Also Here is the code for the CodeGen Method.
public static class CodeGen
{
public static TDelegate CreateDelegate<TDelegate>(Action<ILGenerator> genFunc, string name = "", object target = null, bool restrictedSkipVisibility = false)
where TDelegate:class
{
ArgumentValidator.AssertGenericIsDelegateType(() => typeof(TDelegate));
ArgumentValidator.AssertIsNotNull(() => genFunc);
var invokeMethod = typeof(TDelegate).GetMethod("Invoke");
var #params = invokeMethod.GetParameters();
var paramTypes = new Type[#params.Length + 1];
paramTypes[0] = target == null ? typeof(object) : target.GetType();
#params.ConvertAll(p => p.ParameterType)
.CopyTo(paramTypes, 1);
var method = new DynamicMethod(name ?? string.Empty, invokeMethod.ReturnType, paramTypes, restrictedSkipVisibility);
genFunc(method.GetILGenerator());
return method.CreateDelegate<TDelegate>(target);
}
}
See the important note at http://msdn.microsoft.com/en-us/library/74x8f551.aspx, which also applies here:
If method is static (Shared in Visual Basic) and its first parameter
is of type Object or ValueType, then firstArgument can be a value
type. In this case firstArgument is automatically boxed. Automatic
boxing does not occur for any other arguments, as it would in a C# or
Visual Basic function call.
The implication is that the first argument to your dynamic method will need to be of type object, and you'll need to do a ldarg_0 followed by an unbox before doing the constrained call.

C#: How can I use implicit cast operator during object to type conversion?

HI!
Here is my case: I have some value type which is wrapped into another type with appropriate implicit converters. If I cast wrapped type to an object and then try to get original value I can do that in two-step cast only.
If simplified my code is as follows:
public enum MyEnum : int
{
First,
Second
}
public class Test<T>
{
public Test(T val)
{
Value = val;
}
private T Value { get; set; }
public static implicit operator T(Test<T> m)
{
return m.Value;
}
public static implicit operator Test<T>(T m)
{
var res = new Test<T>(m);
return res;
}
}
static void Main()
{
object res = new Test<MyEnum>(MyEnum.First);
Console.WriteLine((MyEnum)(Test<MyEnum>)res);
Console.WriteLine((MyEnum)res);
}
First "Console.WriteLine" works OK. Second one fails.
Is there any way I can modify this behavior and get it working without double casting?
UPDATE 1
I must use object to value cast (in real application I have to cast ComboBox.SelectedItem property and I do not want to add extra property to ComboBox, because I'll have to change my UI interaction code everywhere).
UPDATE 2
Implicit conversions to and from System.Object are not allowed.
UPDATE 3
Updated my sample code to reflect the whole problem.
Don't use object that way. Write your first line like this instead:
Test res = new Test(1);
If you must have it in an object first, remember that all the compiler knows about it at this point is that it's an object, and nothing more. You, as the programmer, have additional information about what you expect this object to be, but for the compiler to take advantage of that information you have to put it into your code somewhere.
Update:
I'm glad I was able to find this again, because this almost-very-timely article by Eric Lippert, who works on the C# language design, went up this morning and explains the problem in depth:
http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx
If you want to simplify casting and not care performance effect, then create extension method.
public static T To<T>(this object obj) {
Type type = obj.GetType();
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo method = methods.FirstOrDefault(mi => (mi.Name == "op_Implicit" || mi.Name == "op_Explicit") && mi.ReturnType == typeof(T));
if (method == null)
throw new ArgumentException();
return (T)method.Invoke(null, new[] { obj });
}
Usage
Console.WriteLine(res.To<MyEnum>());
Instead of adding implicit operators, consider implementing IConvertible. You only need to implement the ToInt32 method, the others are meaningless and you can throw the InvalidCastException in the other methods.
After that, you can use Convert.ToInt32() method to convert your object in one step.
or even
var res = new Test(1);
Your local variable res is always of type object; so the line that isn't working is trying to convert an object, that isn't an int, to an int, which can't be done. Same as this fails:
object d = 5.5d;
Console.WriteLine((int)d);
EDIT:
Perhaps a pattern that might help is something like this:
if (res.GetType() == typeof(Test))
{
Console.WriteLine((int)(Test)res);
}
else
{
Console.WriteLine((int)res);
}
It's a very localized solution to your problem, but perhaps it will work for you.
While the error is due to res being of type object, I would make the Test->int operator explicit...

Categories