Strange behavior of dynamic objects - c#

I have a simple control method DoSomething which receives a json string, converts it to a dynamic object and tries to get the data:
[HttpPost]
public string DoSomething(string jsonStr) // {"0":null,"1":"loadData"}
{
// In this case obj.GetType() = System.Web.Helpers.DynamicJsonObject
object obj = Json.Decode(jsonStr);
// Correct, a == "loadData"
var a = (obj as dynamic)["1"];
// Incorrect, compilation exception:
// "Cannot apply indexing with [] to an expression
// of type 'System.Web.Helpers.DynamicJsonObject'"
var b = (obj as DynamicJsonObject)["1"]
return "OK";
}
My question is why it is possible to access an indexer when I use an object as a dynamic object at the time when the original type doesn't have an indexer?

In the first case, you're using all the infrastructure of dynamic - which doesn't just use reflection to find "real" members, but also uses IDynamicMetaObjectProvider to provide support for members which are only known at execution time. This works because when you're using dynamic, the process of binding (working out what a member name means) is performed at execution time instead of at compile time.
In this case, it's the indexer which is being used at execution time - DynamicJsonObject doesn't declare an indexer, but overrides the TryGetIndex method of DynamicObject. The meta-object provider implementation of DynamicObject will route indexer "get" calls via TryGetIndex.
A simpler example of this is ExpandoObject:
ExpandoObject foo = new ExpandoObject();
// This is invalid; the compiler can't find a Property member
foo.Property = "broken";
dynamic bar = foo;
// This is fine; binding is performed at execution time.
bar.Property = "working";

Related

C# - Determine if Method ReturnType is of a specific Type

I have a class named PathInfo. Several of the methods in my project return a Task<PathInfo>.
I'm getting the methods in my project via reflection. I need to see if a method returns a Task<PathInfo>. My question is, how do I do that?
At this time, I have a MethodInfo instance. I noticed that the MethodInfo instance has a property named ReturnType. However, I don't know how to use that property to determine if the ReturnType is a Task<PathInfo>. Any ideas?
ReturnType will return a Type object. You should be able to simply compare this to your type to see if they match:
var isOfType = methodInfo.ReturnType == typeof(Task<PathInfo>);
if the type you are comparing to varies then as long as you have it as a type object you can do much the same with a variable of type Type:
Type myType = typeof(Task<PathInfo>); // Assignment as an example - this type could easily come from a method parameter or elsewhere
var isOfType = methodInfo.ReturnType == myType;

Cast a less specified interface IInterface to a more specified IInterface<TKey,TValue>?

I have two interfaces
public interface ISerializableDictionary { ... }
public interface ISerializableDictionary<TKey,TValue>
: ISerializableDictionary { ... }
I need to cast from the former to the latter at run time using reflection.
It's clearly easy to interrogate the former with GetType().GetGenericArguments.
But how do I then do the cast? I have this code below but it is failing to compile, for the obvious reason that I am trying to use a variable as a type.
Type[] genericTypes = dictionary.GetType().GenericTypeArguments;
Type keyType = genericTypes[0];
Type valueType = genericTypes[1];
// this compiles but doesn't do the cast
Type dictType = typeof(SerializableDictionary<,>).MakeGenericType(keyType, valueType);
var createdDictionary = Activator.CreateInstance(dictType);
// this is the line that won't compile - 'dictionary' is a SerializableDictionary, and I want to access it through its typed generic interface
ISerializableDictionary<keyType,valueType> serializableDictionary = dictionary as ISerializableDictionary<keyType, valueType>;
The more specified interface has a method which I need to call. The less specified interface does not (and can't ever be, because the call needs a typed argument).
Is the solution something to do with dictionary.GetType().GetInterfaces()?
Any steer will be wildly appreciated. Programming solo at the moment so I don't have a team to call on, hence the query here.
UPDATE - in response to comments
The problem I am trying to solve is how to serialize members of an object where the members are themselves enumerable. I am trying to figure out how serialization libraries do it as a learning exercise and because I have a few ideas that I want to explore. Serialization & Reflection are not my main areas of programming so I am stumbling to learn them.
So I have (as reduced code):
public class ExperimentalSerializer<T>
{
public void Serialize(T objectToSerialize)
{
IEnumerable<object> collectionsToSerializeToCSV = objectToSerialize.GetEnumerableMembers();
foreach (object collectionToSerialize in collectionsToSerializeToCSV)
{
string csvString = "";
if (collectionToSerialize.IsDictionary())
{
// serialize dictionary here to csvString
// but cannot properly access contents through just IDictionary
// need IDictionary<TKey,TValue>
// ** ALSO SEE TEXT BELOW THIS CODE SNIPPET**
}
else if (collectionToSerialize.IsList())
{
// serialize list here to csvString
}
else if (collectionToSerialize.GetType().IsArray)
{
// serialize array here to csvString
}
// save csvString to somewhere useful here
}
}
}
And elsewhere I have an extension method:
public static IEnumerable<object> GetEnumerableMembers(this object objectToInterrogate)
{
Type objectType = objectToInterrogate.GetType();
// get the enumerable properties
PropertyInfo[] properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
IEnumerable<PropertyInfo> enumerableProperties = properties.Where(propertInfo => propertInfo.PropertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)));
IEnumerable<PropertyInfo> serializableProperties = enumerableProperties.Where(p => p.IsSerializable());
IEnumerable<object> enumerablePropertyValues = serializableProperties.Select(p => p.GetValue(objectToInterrogate, null));
// get the enumerable fields
FieldInfo[] fields = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public);
IEnumerable<FieldInfo> enumerablefields = fields.Where(propertInfo => propertInfo.FieldType.GetInterfaces().Any(x => x == typeof(IEnumerable)));
IEnumerable<object> enumerablefieldValues = enumerablefields.Select(f => f.GetValue(objectToInterrogate));
// merge the two lists together
IEnumerable<object> enumerableMembers = enumerablePropertyValues.Union(enumerablefieldValues);
return enumerableMembers.ToList();
}
One specific challenge I am investigating is how to serialize an enumerable (Dictionary, List or array TValue[]) where TValue is itself a complex type (e.g. a class that can be serialized). This cannot be ascertained without knowing the type of TValue, but this cannot be retrieved from IDictionary or IList alone and these can only be enumerated with the type object.
This is the very specific point I am trying to investigate and potentially to control: how to determine TValue and then to work out if/how to serialize it in turn. My idea is to cast to more-specified generics with known type parameters but I get a bit lost at this point.
Hope this helps.
#SLaks points out in the comments:
Casting is inherently a compile-time operation. Casting to a type only known at runtime makes no sense. You can't call your method if its types are not known at compile-time.
That's absolutely right. You can, of course, still call the intended method at runtime, but you'll need to use (more) reflection to do it, since you have no way to get the compiler to generate a statically-typed call.
To do this, take the Type object you already constructed using MakeGenericType(), and call GetMethod() on it to get the Type.MethodInfo object corresponding to the method to call. Then, call MethodInfo.Invoke().
Type dictType = typeof(SerializableDictionary<,>).MakeGenericType(keyType, valueType);
MethodInfo method = dictType.GetMethod("MyMethod");
object returnValue = method.Invoke(dictionary, new object[] { /* arguments */ });
TMI...
When you write dictionary.MyMethod(), the C# compiler generates a Callvirt IL (byte code) instruction. The object to call the method on (and the arguments to the method) are pushed onto the stack, and the argument to Callvirt is the metadata token corresponding to the type-qualified ISerializableDictionary<TKey,TValue>.MyMethod method. This is the normal calling mechanism in .NET. When you (and the compiler) don't know what TKey and TValue are at compile time, there's no way to get the right metadata token for the method, and no way to generate the Callvirt. That's why you have to use the reflection API.
You can, however, use something like DynamicMethod to generate your own IL and JIT it at runtime. Once JITted, the call is just as fast as one statically generated by the compiler. There is of course significant overhead to generating a dynamic method, but it's a one-time overhead.
Of course, #DavidL points out:
The approach here seems wildly off-course. Instead of asking for a specific solution, can you please describe the specific concrete problem that you are trying to solve?
That, too, is absolutely right. So don't do what I just suggested unless you really, really know what you're doing and have a really, really good reason. (Hint: You don't.) But I thought this information might give you a better overall picture of why you can't do what you expected to do.

How can I determine if an object of anonymous type is empty?

I am sure the answer to this is quite simple but I am trying to write an if statement (C# 5.0) to determine whether or not an anonymous type is empty or not. Here is a simplified version of my code:
public void DoSomething(object attributes)
{
// This is the line I need??
if (atrributes != new {}) {
}
}
The attributes variable gets created dynamically depending on what is needed and sometimes it is empty.
So how do I determine if an anonymous type is empty?
Anonymous types do not provide operator overloads for ==, although it wouldn't matter in this case since one of the arguments is typed object. However the C# compiler does provide Equals, GetHashCode, and ToString implementations.
Use the static object.Equals, method which will do the appropriate null checks and then call the virtual Equals method on the first argument:
object.Equals(attributes, new { });
You could also cache a static instance if you were concerned about the overhead of an allocation for each comparison.
If by empty you mean no properties, you can use reflection:
var o1 = new {};
o1.GetType().GetProperties().Count(); //==0
var o2 = new {test=1};
o2.GetType().GetProperties().Count(); //==1

Dapper: What's the difference between these two pieces of code?

I've registered a custom type handler for Dapper to Json serialize a string. This works as expected. However, whilst coding, I discovered two pieces of code after refactoring, the latter one which didn't trigger the datatype handler, but should in my opinion, so what's the difference?
First the code that works as expected - the custom type handler is called by dapper, and the data is serialized when inserted into the table:
if (val.GetType() != typeof (String))
{
var v = new JsonString {Value = val};
this.Connection.Execute("insert into misc (k,v) values (#keyName, #v)",
new { keyName, v });
}
else
{
this.Connection.Execute("insert into misc (k,v) values (#keyName, #val)",
new { keyName, val });
}
Now for the code which doesn't work as it inserts into the table the fully qualified type string instead of the serialized data, but which I think is semantically similar:
var v = val.GetType() != typeof (String)
? new JsonString {Value = val}
: val;
// t is set to type of JsonString, therefore the dapper type handler should be used
var t = v.GetType();
this.Connection.Execute("insert into misc (k,v) values (#keyName, #v)",
new { keyName, v });
Is it a dapper bug or a c# oddity? I assume it's something to do with the auto typing in the ternary conditional which is the failing point, but t is set to the data type that is serialized by Dapper (or rather the custom type handler). What's the difference?
I am going to assume that the compile-time type (i.e. declaration type) of val is System.Object. I will explain why the two situations are not equivalent.
One must be careful to distinguish between the compile-time type of a variable and the actual run-time type (which is found by .GetType()).
In the first piece of code, in the branch where val is not String at run-time, we declare:
var v = new JsonString {Value = val};
Here var is substituted by JsonString since that is the compile-time type of the right-hand side of the = assignment. Then the anonymous type instance:
new { keyName, v }
is going to be a class (I will call it class Anonymous1) with a member
public JsonString v { get { ... } }
Now, in the second piece of code, we have instead:
var v = val.GetType() != typeof (String)
? new JsonString {Value = val}
: val;
The compile-time types of the operands to the ternary operator are:
{bool} ? {JsonString} : {object}
At compile-time, a best common type for JsonString and object must be found. That common type is object. So object becomes the compile-time type of v here, i.e. var means object here.
Then the anonymous type:
new { keyName, v }
is a type "Anonumous2" whose "2nd" property reads:
public object v { get { ... } }
So to sum up: In the first case you pass in an object which has a property v declared as a JsonString which when retrieved returns a JsonSting that happens to have run-time JsonString. In the second code sample you pass in an object which has a property v declared as object which when retrieved returns an object that happens to have run-time type JsonString.
I do not know much on how Dapper works! But presumably when it sees (by reflection?) that the property type is object, it simply calls .ToString() on it. If that object happens to be of run-time type string, that should be OK, since string.ToString() is overridden. But JsonString.ToString() is not like that.
When Dapper sees the property is declared as JsonString, Dapper does something smarter than calling .ToString().
Assuming there is no implicit conversion available between JsonString and String, the code in the second example won't work. If there is an implicit conversion available, you need to provide more information about the exception that is occurring.
WIth no conversion available between JsonString, a variable declared with type var has a type that is inferred by the compiler ((https://msdn.microsoft.com/en-us/library/bb384061.aspx). In this case, variable v is either of type JsonString or String depending upon which part of the assignment occurs. If the compiler assumes it is of type JsonString, any assignment with a String will fail.
In your second code example, the first line of code is wrong since the assignment results in two different data types getting assign to variable v.

How can I pass a type, rather than an instance, to a function in C#?

I am attempting to use reflection to enumerate class fields and methods in order to do some automation in a web application. I am also abstracting this so that I could pass in any class.
Is there a way I could somehow pass in the type directly to a function to enumerate on rather than an instance of the type?
I would like the caller side to look like this:
var m = new MyClass(AClassOfSomeTypeIDefined);
I would like to avoid creating an instance as that is misleading to anyone who might use the class (as the instance isn't directly used).
using System;
public void UseType(Type t) {
// do something with t using reflection techniques - e.g.
Console.WriteLine("compat with int? {0}", typeof(int).IsAssignableFrom(t));
}
Call it with C# typeof keyword and the data type you want to pass.
// Examples...
UseType( typeof(int) );
UseType( typeof(System.Int32) );
UseType( typeof(System.Windows.Controls.Button) );
UseType( typeof(IDisposable) );
UseType( typeof(WhateverTypeYouWant) );
System.Type is one of the cornerstones of reflection as you already know, so run with it.
Other notes
Depending on what you want to do with the type, the following peripheral details might be useful.
To create an instance of a Type at runtime without having used the new keyword at compile time, use the System.Activator class. e.g.
// Create a List of strings like: new List<string>();
var list = (List<string>) Activator.CreateInstance( typeof(List<string>) );
yes just use the Type of your class. There's two basic ways to get the type:
Foo foo = new Foo();
Type myType = foo.GetType();
Type myTyp2 = typeof(Foo);
You can use GetType() if you only know the type at runtime (more common with reflection), or typeof() if you know the type at compile time already.
In your example this would be i.e.
var m = new MyClass(typeof(Foo));
You can pass a Type object just like any other parameter.
class MyClass
{
public MyClass(Type yourType)
{
// do as you please with yourType
}
}
The call it:
var m = new MyClass(typeof(YourType));

Categories

Resources