Unpredictible behaviour in c# dynamic - c#

I've found a bug (feature?) during learning dynamic in C#. Can anyone explain me, why do I have an exception??
static class Program
{
public static void Main(string[] args)
{
dynamic someObj = ConstructSomeObj((Action)(() => Console.WriteLine("wtf")));
var executer = someObj.Execute;
executer(); // shows "wtf"
someObj.Execute(); // throws RuntimeBinderException
Console.ReadKey();
}
static dynamic ConstructSomeObj(dynamic param)
=> new { Execute = param };
}
Note: typeof both exectuer and someObj is dynamic

Let's look at following code:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("first");
// works perfectly!!!
dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
foo.x();
// fails
dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
foo2.x();
}
}
dynamic uses reflection to access objects method and fields and since it cannot know exact types it must rely on type information present in objects on which it operate.
When field x in anonymous type is properly typed as delegate invocation foo.x() works because dynamic can see that field value is delegate.
When you use
static dynamic ConstructSomeObj(dynamic param)
{ return new { x = param }; }
to create anonymous class you created class with field x of type object (dynamic is object behind the scenes). When you call obj.x dynamic sees that field type is an object and it does't bother to check to what exact type this field points. And since object doesn't have Invoke() method like delegates it throws exception. If you change method parameter type to Action it will work.
I guess this decision to check field type instead of type of value that field contains was taken to provide better performance. In other words when you check field type CallSite class generated by dynamic can be cached and reused later.
References:
https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/Binder.cs
https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpInvokeMemberBinder.cs
EDIT: Checked this on mono, can somebody verify on VS

ok, interesting. This 2 Lines would work:
Task.Run(someObj.Execute);
((Action)someObj.Execute)();
It seems that the compiler does accept the () for dynamic types always and at runtime the CLR only looks 'one level deep'. So you can help here by adding explicit cast or do the cast implicit with the Task.Run(). If this is a feature or a bug!? ... no idea ;-) ...

Related

Unable to cast '<T>d__14`1[System.Object] to 'IEnumerable`1[System.Int32]'

I'm trying to create generator of IEnumerable to set School.Foundation,
this is the Type that I'm trying to populate at the moment:
public class School
{
public IEnumerable<int> Foundation;
}
this is my generator so far:
public static IEnumerable<T> GetEnumerable <T>(Func<T> f)
{
while(true)
{
yield return f();
}
}
So what I'm doing is the following reflection:
Dictionary<string, Func<object>> funcMembers;
public static object Generator(String name, Type t)
{
Func<object> func;
if (funcMembers.TryGetValue(name, out func))
{
if (t.Name.StartsWith("IEnumerable"))
return GetEnumerable(func);
}
}
I made the following test to check if it was fully functional:
[TestMethod]
public void Test_generator()
{
private Dictionary<string, Func<object>> funcMembers = new Dictionary<string, Func<object>>();
//adding the Field "Foundation" generator on the dictionary
funcMembers.Add("Foundation", () => {return 4;});
School s = new School();
// calling my Generator that should return IEnumerable<int>
s.Foundation = Generator(
"Foundation",
typeof(School).GetField("Foundation").
Assert.IsNotNull(s.Foundation);
}
i have the following error when I'm on line:
s.Foundation = Generator(
"Foundation",
typeof(School).GetField("Foundation").
the error is the following:
> Unable to cast object of type '<GetEnumerable>d__14`1[System.Object]'
> to type 'System.Collections.Generic.IEnumerable`1[System.Int32]'.
Your funcMembers contain this:
funcMembers.Add("Foundation", () => {return 4;});
the right-hand-side is an anonymous delegate, parameterless, returning constant 4. It is implicitely typed as Func<object> soit can be added to the dictionary. As all delegates, compiler compiles it as a class, but since it doesn't have name, a special name of "d__14`1[System.Object]" is automatically generated.
Then, it seems that either Generator or GetEnumerable method return this delegate object directly, instead of invoking it and getting the value of 4 and wrapping it into IEnumerable.
This delegate returned from Generator or GetEnumerable is then assigned to s.Foundation, which causes this error you noticed (since the anonymous class of the delegate obviously doesn't implement IEnumerable).
I bet you can see all of that simply by stepping with the debugger.For a better view, write it like that:
var tmp = Generator(
"Foundation",
typeof(School).GetField("Foundation")...
s.Foundation = tmp;
and observe the value in TMP and then, well, diagnose what's up (ie. by stepping into Generator and seeing what happens there) and fix it.
Side note: This is as far as got with these code scraps you pasted. I can't tell you more about your problem, because the code you provided contains severe errors (i.e Generator - not all code paths return value), some lines are incomplete (where's the end of typeof(School).GetField("Foundation").?) and so on.
In such cases, please try to provide minimal complete example which actually compiles.

Implicit conversion from IEnumerable<int> to IEnumerable<dynamic>

I haven't used dynamic much in C# so far, so I came across a (small) problem when trying to create a simple WebGrid-like component for learning purposes.
The normal WebGrid takes as its data source an IEnumerable<dynamic>, so I emulated that. Then I created a view like the following:
#model IEnumerable<int>
#{
MyWebGrid grid = new MyWebGrid(Model);
}
In the MVC project, this leads to a runtime conversion error, so I created a small console application (this doesn't compile of course):
class Program
{
class Foo { public int Id { get; } }
static void Main()
{
CheckConversion(new List<int>().AsEnumerable()); // Error
CheckConversion(new List<Foo>()); // works
int x = 5;
CheckSingleParameterConversion(x); // works
}
private static void CheckConversion(IEnumerable<dynamic> source) { }
private static void CheckSingleParameterConversion(dynamic val) { }
}
The error (in short): Cannot convert from IEnumerable<int> to IEnumerable<dynamic>.
What is the exact reasoning behind these differing behaviors? I know that dynamic is a reference type and could thus understand why there might be some problem with the IEnumerable<int> here, but why does it work in the single parameter case then?
Problem is not in dynamic itself, it's all about variance.
As said in MSDN
Variance applies only to reference types; if you specify a value type
for a variant type parameter, that type parameter is invariant for the
resulting constructed type.
So IEnumerable<int> cannot be casted to IEnumerable<dynamic>, because int is a value type and dynamic is just an object marked with special attribute.

Dynamic type with lists in c#

I have a little problem for you guys.
I would like to do this:
Type[] classes = new Type[]{ Class1, Class2 };
foreach(Type t in classes){
List<t> list = new List<t>();
}
Is there some way to do this?
You cannot cast to a generic type at runtime, because the type in the generic needs to be resolved at compile time.
You can create a generic type in a dynamic manner using reflection, but unless you hard-code the cast, all you get in return is an object.
I cannot really tell what it is you want, I have to agree with a comment this is an XY problem. I would be inclined to make the presumptuous statement that there is a design issue somewhere that this is trying to solve, instead of addressing the design issue directly, or asking the question of what you are trying to achieve directly.
You can use the following code to create the type, then the dynamic type can be used to duck type the various members of List<T> without knowing/caring that it is a list or what T is:
using System;
using System.Collections.Generic;
namespace ConsoleApplication61
{
class Program
{
static void Main(string[] args)
{
dynamic o = CreateGeneric(typeof(List<>), typeof(int));
o.Add(1);
Console.WriteLine(o[0]);
Console.Read();
}
public static object CreateGeneric(Type generic, Type innerType, params object[] args)
{
System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
return Activator.CreateInstance(specificType, args);
}
}
}
The above sample duck types the Add method and the Indexer. The DLR does the type handling and the duck typing at runtime - knowing that 1 is an int, for example.
Just to clarify, I likely wouldn't use such code in production (unless you requirements are very specific to need this) and any issues with type-mismatching will occur at run time; so you either need to type very accurately (limited IntelliSense) or have good error handling.
Thanks to this blog post for the CreateGeneric method.
This assumes .NET 4 with the new CLR. As #MartinLiversage has also pointed out, this particular sample assumes that you are utilising the list in a sort-of-strongly-typed manner. In my example I am passing an int to a List<int> hidden in a dynamic.
We have been on .NET 4 almost since it was released. We have a large application with an even larger code base. dynamic isn't used once in the application, and only a few times in the test code base. That isn't to say "don't use it", it's to say "most of the time, you don't need it".
You can do it like this:
foreach(Type t in classes)
{
var listType = typeof(List<>).MakeGenericType(t);
var instance = Activator.CreateInstance(listType);
}
This is possible with the Type.MakeGenericType Method
Here's a nifty method I found that should work for ya: CodeRef
public static object CreateGeneric(Type generic, Type innerType, params object[] args)
{
System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
return Activator.CreateInstance(specificType, args);
}
And use it like so:
var o = CreateGeneric(typeof(List<>), t);
Unfortunately, to add items you'll have to do it like so (where item is the item you're adding).
MethodInfo addMethod = o.GetType().GetMethod("Add");
addMethod.Invoke(o, new object[] { item.ToType(t) });
Or use the Generic type as mentioned in another answer.
You can try this:
Type[] classes = new Type[] { typeof(A), typeof(B) };
foreach (Type t in classes)
{
Type genericType = typeof(List<>).MakeGenericType(t);
var list = Activator.CreateInstance(genericType);
}
If you want to keep to objects in one list then probably they have something in common.
In such case, I would argue that, just like L.B mentioned in a comment, you are asking a wrong question here.
Probably it's a design issuethat you have. Think about those types, see what they have in common and think about deriving from one base type or make both implement the same interface. In such case you would be able to instantiate a list of the objects of the base type/interface and work with those.
Just to give you a head start:
abstract class Vehicle {
public int NumberOfWheels { get; set; }
}
class Car : Vehicle
{
public Car()
{
NumberOfWheels = 4;
}
}
class Bicycle : Vehicle
{
public Bicycle()
{
NumberOfWheels = 2;
}
}
static void Main(string[] args)
{
var v1 = new Car();
var v2 = new Bicycle();
var list = new List<Vehicle>();
list.Add(v1);
list.Add(v2);
foreach (var v in list)
{
Console.WriteLine(v.NumberOfWheels);
}
Console.ReadKey();
}

How to cast instance of Enumerable<T>.Where(Predicate) to IEnumerable<T>?

I'm writting a c# code generator. In some place I must cast return type of Linq's method like WhereSelectListIterator to IEnumerable type. How can I do it?
Scenario:
I have an instance of a List named aList. I write following expression in a Textbox:
aList.Where(item => item.StartsWith("s")).Select(item => item.ToUpper()).ToList().Count
I need to write an application to evaluate my expression. I know that i must write an C# code generator to evaluate my expression.
If I evaluate above expression directly it is works. But suppose that I have following scenario :
public Interface IInterface
{
}
public class MyClass:IInterface
{
public int Id = 10;
public IInterface GetInstance()
{
return new MyClass();
}
}
public class Program
{
public static void Main()
{
var myClass = new MyClass();
myClass.GetInstance().Id.ToString();
}
}
When I use Id property after calling GetInstance() method it cause to CLR raise an exception because IInterface hasn't Id property. I need to cast return type of GetInstance() to MyClass first then use Id property.
How can I do this cast dynamically.
One solution is using dynamic object.
var myClass = new MyClass();
dynamic x = myClass.GetInstance();
dynamic y = myClass.Id;
y.ToString();
But dynamic object has problem with Extension methods(ex : Where(), Take() , ...). What can I do?
In answer to the question you ask in the title, The result of Enumerable<T>.Where(Predicate) implements IEnumerable<T>, just cast it, no need to do anything fancy. See here: Enumerable..Where(TSource) Method (IEnumerable(TSource), Func(TSource, Boolean))
As for the rest, why are you trying to generate C# code? If you're trying to evaluate a code snippet that was entered at runtime, why not use the C# compiler to compile it? I Googled for "C# programmatic compilation", and the first result was this Microsoft support page: How to programmatically compile code using C# compiler
You can call extension methods on dynamic objects like this:
dynamic result = Enumerable.Where(collection, (Func<dynamic, bool>)delegate(dynamic item)
{
return item.Id == id;
});

Internal Workings of C# Virtual and Override

The topic of how C# virtual and override mechanism works internally has been discussed to death amongst the programmers... but after half an hour on google, I cannot find an answer to the following question (see below):
Using a simple code:
public class BaseClass
{
public virtual SayNo() { return "NO!!!"; }
}
public class SecondClass: BaseClass
{
public override SayNo() { return "No."; }
}
public class ThirdClass: SecondClass
{
public override SayNo() { return "No..."; }
}
class Program
{
static void Main()
{
ThirdClass thirdclass = new ThirdClass();
string a = thirdclass.SayNo(); // this would return "No..."
// Question:
// Is there a way, not using the "new" keyword and/or the "hide"
// mechansim (i.e. not modifying the 3 classes above), can we somehow return
// a string from the SecondClass or even the BaseClass only using the
// variable "third"?
// I know the lines below won't get me to "NO!!!"
BaseClass bc = (BaseClass)thirdclass;
string b = bc.SayNo(); // this gives me "No..." but how to I get to "NO!!!"?
}
}
I think I can't get to the methods of base class or the intermediate derived class simply using the most derived instance (without modifying the method signatures of the 3 classes). But I would like to confirm and cement my understanding...
Thanks.
C# can't do this but it is actually possible in IL using call instead of callvirt. You can thus work around C#'s limitation by using Reflection.Emit in combination with a DynamicMethod.
Here's a very simple example to illustrate how this works. If you really intend to use this, wrap it inside a nice function strive to make it work with different delegate types.
delegate string SayNoDelegate(BaseClass instance);
static void Main() {
BaseClass target = new SecondClass();
var method_args = new Type[] { typeof(BaseClass) };
var pull = new DynamicMethod("pull", typeof(string), method_args);
var method = typeof(BaseClass).GetMethod("SayNo", new Type[] {});
var ilgen = pull.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.EmitCall(OpCodes.Call, method, null);
ilgen.Emit(OpCodes.Ret);
var call = (SayNoDelegate)pull.CreateDelegate(typeof(SayNoDelegate));
Console.WriteLine("callvirt, in C#: {0}", target.SayNo());
Console.WriteLine("call, in IL: {0}", call(target));
}
Prints:
callvirt, in C#: No.
call, in IL: NO!!!
Without modification to your sample and discounting reflection, no there is no way. The intent of the virtual system is to enforce calling the derived most no matter what and the CLR is good at its job.
There are a couple of ways you can work around this though.
Option 1: You could add the following method to ThirdClass
public void SayNoBase() {
base.SayNo();
}
This would force the invocation of SecondClass.SayNo
Option 2: The main problem here is that you want to invoke a virtual method non-virtually. C# only provides one way of doing this via the base modifier. This makes it impossible to call a method within your own class in a non-virtual fashion. You can fix this by factoring it out into a second method and proxying.
public overrides void SayNo() {
SayNoHelper();
}
public void SayNoHelper() {
Console.WriteLine("No");
}
Sure...
BaseClass bc = new BaseClass();
string b = bc.SayNo();
"Virtual" means that the implementation which will be executed is based on the ACTUAL type of the underlying object, not the type of the variable it is stuffed in... So if the actual object is a ThirdClass, that's the implementation you will get, no matter what you cast it to. If you want the behavior you describe above, don't make the methods virtual...
If you're wondering "what's the point?" it's for 'polymorphism'; so that you can declare a collection, or a method parameter, as some base type, and include/ pass it a mix of derived types, and yet when, within the code, even though each object is assigned to a ref variable declared as the base type, for each one, the actual implementation which will be executed for any virtual method call will be that implementation defined in the class definition for the ACTUAL tyoe of each object...
Using base in C# only works for the immediate base. You can't access a base-base member.
It looks someone else beat me to the punch with the answer about it being possible to do in IL.
However, I think the way I did the code gen has some advantages, so I'll post it anyways.
The thing I did differently is to use expression trees, which enable you to use the C# compiler to do overload resolution and generic argument substitution.
That stuff is complicated, and you don't want to have to replicate it your self if you can help it.
In your case, the code would work like this:
var del =
CreateNonVirtualCall<Program, BaseClass, Action<ThirdClass>>
(
x=>x.SayNo()
);
You would probably want to store the delegate in a readonly static field, so that you only have to compile it once.
You need to specify 3 generic arguments:
The owner type - This is the class that you would have invoked the code from if you were not using "CreateNonVirtualCall".
The base class - This is the class you want to make the non virtual call from
A delegate type. This should represent the signature of the method being called with an extra parameter for the "this" argument. It's possible to eliminate this, but it requires more work in the code gen method.
The method takes a single argument, a lambda representing the call. It has to be a call, and only a call. If you want to extend the code gen you can support more complex stuff.
For simplicicty, the lambda body is restricted to only being able to access lambda parameters, and can only pass them in directly to the function. You can remove this restriction if you extend the code gen in the method body to support all expression types. That would take some work though. You can do anything you want with the delegate that comes back, so the restriction isn't too big of a deal.
It's important to note that this code is not perfect. It could use a lot more validation, and it doesn't work with "ref" or "out" parameters because of expression tree limitations.
I did test it in sample cases with void methods, methods returning values, and generic methods, and it worked. I'm sure, however, you can find some edge cases that don't work.
In any case, here's the IL Gen Code:
public static TDelegate CreateNonVirtCall<TOwner, TBase, TDelegate>(Expression<TDelegate> call) where TDelegate : class
{
if (! typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
{
throw new InvalidOperationException("TDelegate must be a delegate type.");
}
var body = call.Body as MethodCallExpression;
if (body.NodeType != ExpressionType.Call || body == null)
{
throw new ArgumentException("Expected a call expression", "call");
}
foreach (var arg in body.Arguments)
{
if (arg.NodeType != ExpressionType.Parameter)
{
//to support non lambda parameter arguments, you need to add support for compiling all expression types.
throw new ArgumentException("Expected a constant or parameter argument", "call");
}
}
if (body.Object != null && body.Object.NodeType != ExpressionType.Parameter)
{
//to support a non constant base, you have to implement support for compiling all expression types.
throw new ArgumentException("Expected a constant base expression", "call");
}
var paramMap = new Dictionary<string, int>();
int index = 0;
foreach (var item in call.Parameters)
{
paramMap.Add(item.Name, index++);
}
Type[] parameterTypes;
parameterTypes = call.Parameters.Select(p => p.Type).ToArray();
var m =
new DynamicMethod
(
"$something_unique",
body.Type,
parameterTypes,
typeof(TOwner)
);
var builder = m.GetILGenerator();
var callTarget = body.Method;
if (body.Object != null)
{
var paramIndex = paramMap[((ParameterExpression)body.Object).Name];
builder.Emit(OpCodes.Ldarg, paramIndex);
}
foreach (var item in body.Arguments)
{
var param = (ParameterExpression)item;
builder.Emit(OpCodes.Ldarg, paramMap[param.Name]);
}
builder.EmitCall(OpCodes.Call, FindBaseMethod(typeof(TBase), callTarget), null);
if (body.Type != typeof(void))
{
builder.Emit(OpCodes.Ret);
}
var obj = (object) m.CreateDelegate(typeof (TDelegate));
return obj as TDelegate;
}
You can't get to the base methods of an override. No matter how you cast the object, the last override in the instance is always used.
If its backed with a field you could pull out the field using reflection.
Even if you pull off the methodinfo using reflection from typeof(BaseClass) you will still end up executing your overridden method

Categories

Resources