views:

1251

answers:

6

I need to cast a property to its actual type dynamically. How do I/Can I do this using reflection?

To explain the real scenario that I am working on a bit. I am trying to call the "First" extension method on an Entity Framework property. The specific property to be called on the Framework context object is passed as a string to the method (as well as the id of the record to be retrieved). So I need the actual type of the object in order to call the Frist method.

I can't use the "Where" method on the object as the lambda or delegate method still needs the actual type of the object in order to access the properties.

Also as the object is generated by the Entity Framework I can't cast the type to an interface and operate on that.

This is scenario code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;

namespace NmSpc
{

    public class ClassA
    {
        public int IntProperty { get; set; }
    }

    public class ClassB
    {
        public ClassA MyProperty { get; set; }
    }

    public class ClassC
    {
        static void Main(string[] args)
        {
            ClassB tester = new ClassB();

            PropertyInfo propInfo = typeof(ClassB).GetProperty("MyProperty");
            //get a type unsafe reference to ClassB`s property
            Object property = propInfo.GetValue(tester, null);

            //get the type safe reference to the property
            ClassA typeSafeProperty = property as ClassA;

            //I need to cast the property to its actual type dynamically. How do I/Can I do this using reflection?
            //I will not know that "property" is of ClassA apart from at runtime
        }
    }
}
+3  A: 

Casting is largely a compile-time thing, not really a reflection thing. What exactly do you mean to do, to "cast the property to its actual type"?

There are some options involving generics, but without a clear idea what you want to achieve it is hard to give a good answer. Even with generics (via MakeGenericMethod etc), you'd just have it as a T - but that doesn't actually let you do much with it...

So: what do you want to do once you have it typed...

Marc Gravell
A: 

Having a variable of a specific type is really only useful at compile time, and will not help you at runtime in using it in this way. Try to write the code where you would utilize this... you'll find that it keeps pushing the requirement to know the type to compile time at some level (maybe further up the call chain, but you'll still eventually need to type the concrete type for this to be useful).

One thing to keep in mind, though - if your type is a reference type, the object is still truly the type you've created. It's not like there is a benefit to having the object saved as your type vs. object. This is the beauty of reflection (as well as part of why it works). There really is no reason to try to "change" it's type at runtime in a cast, since it's still going to be an object.

Reed Copsey
+2  A: 
public object CastPropertyValue(PropertyInfo property, string value) { 
if (property == null || String.IsNullOrEmpty(value))
 return null;
if (property.PropertyType.IsEnum)
{
 Type enumType = property.PropertyType;
 if (Enum.IsDefined(enumType, value))
  return Enum.Parse(enumType, value);
}
if (property.PropertyType == typeof(bool))
 return value == "1" || value == "true" || value == "on" || value == "checked";
else if (property.PropertyType == typeof(Uri))
 return new Uri(Convert.ToString(value));
else
 return Convert.ChangeType(value, property.PropertyType);  }
Nisus
A: 

Though I should post the solution to the real world problem.

string objectType = "MyProperty";

using (MyEntitiesContext entitiesContext = new MyEntitiesContext())
{
try
{
    string queryString = @"SELECT VALUE " + objectType+  " FROM MyEntitiesContext." + objectType + " AS " + objectType + " WHERE " + objectType + ".id = @id";

    IQueryable<Object> query = entitiesContext.CreateQuery<Object>(queryString, new ObjectParameter("id", objectId));

    foreach (Object result in query)
    {
        return result;
    }
}
catch (EntitySqlException ex)
{
    Console.WriteLine(ex.ToString());
}
}

return null;

I think the new CLR4 dynamic keywork might be the "nice" solution.

Thanks for all the responces.

Keith K
A: 

I had some time so I tried to solve my problem using VS2010 and I think I was right previously when I though that the dynamic keywork would 'solve' my question. See the code below.

using System.Reflection;

namespace TempTest
{
    public class ClassA
    {
        public int IntProperty { get; set; }
    }

    public class ClassB
    {
        public ClassB()
        {
            MyProperty = new ClassA { IntProperty = 4 };
        }
        public ClassA MyProperty { get; set; }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            ClassB tester = new ClassB();

            PropertyInfo propInfo = typeof(ClassB).GetProperty("MyProperty");
            //get a type unsafe reference to ClassB`s property
            dynamic property = propInfo.GetValue(tester, null);

            //casted the property to its actual type dynamically
            int result = property.IntProperty; 
        }
    }
}
Keith K
A: 

Damn... I want to cast variable to the type, that is stored as string, e.g.: "int32", "string", etc. So that's why i need to use reflection to get REAL type at first and then.. to cast somehow. I do not want to create instance via activator, oh, no! :) I need to assign some stuff to variable (both key and value stored in xml as strings), but before i need to cast to proper type!

Nafiganado