0

Is it possible to cast from a Dynamic or an Object to a variable type? The target variable type is one generic class, only the specific data type varies.

I'm looking for abstract solution, but the situation is this: I want a single Linq2SQL command for different Entities - I can GetProperty + GetValue of the EntityFramework Context, but then it must be casted to some exact types, but these come from variable input - names of DB tables.

Example of what I have:

 Type NewType = typeof(System.Data.Objects.ObjectSet<>);
 NewType.MakeGenericType(new Type[] {"...some type here that's variable accordint to user input - like Person, Address, Contact, ..."});            
 Object MyObject = Context.GetType().GetProperty("the same variable like above - Person, Address,...", BindingFlags.Public | BindingFlags.Instance).GetValue(Context, null); // this is EntityFramework Context

Example of what I need but don't know how to do it:

 NewType CastedObject = (NewType) MyObject;
 // or
 NewType CastedObject = Convert.ChangeType(MyObject, NewType);
 // or
 NewType CastedObject = MyObject as NewType;

so I could do this:

 (from x in CastedObject where x.ID == ID select x).FirstOrDefault();

For those, who are familiar with PHP, I'm trying to do this:

 (from x in Context.$tablename where x.ID == ID select x).FirstOrDefault();
John Saunders
  • 160,644
  • 26
  • 247
  • 397
Jan Matousek
  • 956
  • 3
  • 13
  • 15
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 21 '13 at 18:14

2 Answers2

0

Since NewType is a runtime type, how could you have a variable of compile-time type NewType? The compiler must know the "declared" type of all variables. So what you want is not possible.

Something you can do is cast MyObject to dynamic. Then stuff like foreach (var x in CastedToDynamic) would compile (but no compile-time type checking).

You can't use LINQ on a dynamic expression, though. You will have to rewrite like:

    dynamic found = null;
    foreach (var x in CastedToDynamic)
    {
      if (x.ID == ID)
      {
        found = x;
        break;
      }
    }

Note: Which overload of == to use will be decided at run-time. So even if ID is a (boxed) System.Guid, say, the == will (unbox and) call the overload of == defined inside that struct. So this works.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • Even if the NewType is declared in the EF, but only "dynamically chosen" by variable? – Jan Matousek Mar 21 '13 at 16:41
  • @JanMatousek (Your first comment) There's no chance you can declare a variable of a "non-fixed" type. The closest you get is generic types. But it won't help when you construct the type from "user input". Generic types are still compile-time types, for example with `void MyMethod(T arg) { ... }` the type `T` is bound compile-time. So no luck. – Jeppe Stig Nielsen Mar 21 '13 at 16:52
  • This solution works! foreach(var x in (dynamic)CastedObject) {...} Thanks – Jan Matousek Mar 22 '13 at 10:27
0

Something like this might get at what you are looking at (relies heavily on reflection)

        List<dynamic> mylist = new List<dynamic>();
        dynamic data = new ExpandoObject();
        data.Foo = "foo";
        data.ID = 1;
        mylist.Add(data);

        data = new ExpandoObject();
        data.Foo = "foobar";
        data.ID = 2;
        mylist.Add(data);


        data = new ExpandoObject();
        data.Foo = "foobar2";
        data.ID = 2;
        mylist.Add(data);

        data = new ExpandoObject();
        data.Foo = "foobar2";
        data.ID = 3;
        mylist.Add(data);

        int idiminterestedin = 2;

        var dynamicselected = mylist.Select(d=>((IDictionary<string,object>)d)).Where(d=>
        {
            object id;
            if (d.TryGetValue("ID",out id))
            {
                return (id is int) && (int)id == idiminterestedin;
            }
            return false;
        });

        foreach (var v in dynamicselected)
        {
            Console.WriteLine(v["Foo"]);
        }

        Console.ReadLine();

Though I'd probably skip the ExpandoObject and go straight for a dictionary:

        Dictionary<string, object> data = new Dictionary<string, object>();
        data["Foo"] = "foo";
        data["ID"] = 1;

And then make a generic extension function(s):

static class ExptensionFunction
{
    static T GetValueAs<T>(this Dictionary<string, object> obj, string key)
    {
        return (T)obj[key];
    }

    static bool TryGetValueAs<T>(this Dictionary<string, object> d, string key, out T value)
    {
        object id;
        if (d.TryGetValue(key, out id))
        {
            if (id is T)
            {
                value = (T)id;
                return true;
            }
        }

        value = default(T);
        return false;
    }

    static IEnumerable<Dictionary<string, object>> GetValuesWithKey<T>(this List<Dictionary<string, object>> list, string key, T value)
    {
        return list.Where(d =>
        {
            T id;
            if (d.TryGetValueAs<T>(key, out id))
            {
                return id.Equals(value);
            }
            return false;
        });
    }
}

Inspired by this:

Creating an anonymous type dynamically?

and

Add property to anonymous type after creation

Community
  • 1
  • 1
IdeaHat
  • 7,641
  • 1
  • 22
  • 53