I'm having this issue, I'm using reflection to pull properties from a class but the problem is reflection returns them as an object and I can't get it into my actual type.
Take for example, if this is the class:
public class Row<T>
{
public static explicit operator Row<object>(Row<T> o)
{
return new Row<object>
{
Name = o.Name,
Value = o.Value
};
}
public string Name { get; set; }
public T Value { get; set; }
}
Casting from one say Row<bool> to Row<object> works:
var a = new Row<bool>
{
Name = "Foo",
Value = true
};
var b = (Row<object>)a; // Works
But when I try to go from object to Row<object> it seems to ignore my explicit operator and throw a System.InvalidCastException:
var c = (object) a; // Simulate getting from reflection
var d = (Row<object>) c; // System.InvalidCastException
What am I missing?
Use dynamic instead of object to force runtime real type check:
var c = (dynamic)a;
var d = (Row<object>)c; // Works fine
It will call your Row<T> -> Row<object> cast operator.
The problem here is that casting does not look for a conversion operator unless one is defined on the static type of the value you are trying to cast. In your example the static type of c is object and object neither derives from nor has a conversion operator to Row<object>, resulting in the runtime exception.
It looks like this problem can be easily sidestepped with a better design.
You want to treat any type of Row<T> as a Row<object> and the conversion operator does nothing more than work around the fact that these types are not hierarchically related. So why not make them related and avoid the problem in the first place?
For example:
public abstract class Row
{
public string Name { get; set; }
public object Value { get; protected set; }
}
public class Row<T> : Row
{
public new T Value
{
get { return (T)base.Value; }
set { base.Value = value; }
}
}
This seems to do what you want:
The casting problem is solved because you can now cast any type of Row<T> to the base class Row (which takes over the responsibilities of Row<object> in your initial design) and easily access Name and Value no matter what type the Value is.
The Row.Value setter is protected so you cannot cast a Row<int> to Row and make Value e.g. a string from outside, maintaining type safety.
You can accomplish this with reflection:
public class RowHelper
{
public static Row<object> LoadRow(object o)
{
var type = o.GetType();
return new Row<object>
{
Name = (string)type.InvokeMember("Name", BindingFlags.GetProperty, null, o, null),
Value = type.InvokeMember("Value", BindingFlags.GetProperty, null, o, null)
};
}
}
You would call this with:
var d = RowHelper.LoadRow(c);
Related
I have a generic class that exposes a generic method. This method receives an instance of the generic object as parameter and modifies this instance.
Example class:
public class GenericClass<T>
{
public T GenericMethod(T obj)
{
// modify the object in some (arbitrary) way
IEnumerable<FieldInfo> fields = obj.GetType().GetRuntimeFields();
foreach (FieldInfo field in fields)
{
if (field.FieldType == typeof(string))
{
field.SetValue(obj, "This field's string value was modified");
}
}
return obj;
}
}
If I have a type (abc):
public class abc
{
public string a;
public string b;
public int c;
}
I can call this method as follows:
GenericClass<abc> myGeneric = new GenericClass<abc>();
var myObject = myGeneric.GenericMethod(new abc());
//Confirm success by printing one of the fields
Console.Writeline(((abc)myObject).a);
Now, my actual question:
How would I call this same Generic method, using a type that is only known at run-time (as opposed to type abc above). I also want to instantiate this this as I pass it in to the GenericMethod, just like I did for abc above.
E.g. (I know this is completely wrong)
Type MyType;
GenericClass<MyType> myGeneric = new GenericClass<MyType>();
var myObject = myGeneric.GenericMethod(new MyType());
Due to unknown type success cannot be confirmed by printing the field "a" which may not exist, I could print the value of all string fields, but this is beyond the scope of the question.
To answer your question:
var type = typeof(abc);
object instanceToModify = new abc();
var typeToCreate = typeof(GenericClass<>).MakeGenericType(type);
var methodToCall = typeToCreate.GetMethod("GenericMethod");
var genericClassInstance = Activator.CreateInstance(typeToCreate);
methodToCall.Invoke(genericClassInstance, new[] { instanceToModify });
DEMO
But:
If your type is only known at runtime your instance must be handled in a variable declared as object or dynamic. In that case you can change your method signature to:
public object GenericMethod(object obj)
{
// modify the object in some (arbitrary) way
IEnumerable<FieldInfo> fields = obj.GetType().GetRuntimeFields();
foreach (var field in fields)
{
if (field.FieldType == typeof(string))
{
field.SetValue(obj, "This field's string value was modified");
}
}
return obj;
}
There's no need for a generic class/method.
I am retrieving JSON with different object type in one part.
I made this part as dynamic.
I need to get data from this object so I created class which looks the same as the dynamic data like below:
public class SpecificObject1
{
public string Title{get; set;}
public object[] ViewElements{get; set}
public object AnyAttributes{get; set;}
}
Here is how I want to convert it to this specific object:
var #switch = new Dictionary<Type, Action> {
{ typeof(x), () => jsonObj.Some = jsonObj.Some as SpecificObject1},
{ typeof(y), () => ......}
};
Casting with as returns null.
EDIT:
Changed properties to real one
dynamic contains:
AnyAttributes: {object}
Title: "title"
ViewElements: object[0]
You can´t change the type of an object - be it dynamic or any other compile-time type. Thus even if you assign jsonObj.Some as SpecificObject1 to jsonObj.Some you can´t change its compiletime type (probably dynamic in your case which is a compiletime-type).
This would imply you could to this:
int a = 3;
a = a as string;
Which is obvious non-sense. a is of type int which can´t be changed. So even if you *could cast a to a string you can´t assign the result (which would be of type sting) to a because a actually is of type int.
The same applies to an instance of dynamic:
dynamic b = a as Bar;
This will still evaluate to b being of type dynamic. However if a was a Bar-instance before, the runtime-type of b surely is Bar as well. Anyway you don´t get anything by this cast as the compile-time-type of b is still dynamic - making it a no-op.
EDIT: In order to get a compile-time type which you can use you have to create a new instance of SpecificType based on jsonObj.Some:
var newValue = new SpecificObject {
Title = jsonObj.Some.Title,
ViewElements = jsonObj.Some.ViewElements,
AnyAttributes = jsonObj.Some.AnyAttributes
}
However you can´t assign this to jsonObj.Some and expect the latter to be of type SpecificObject at compile-time. Anyway as it already is dynamic you can do everything you want with it, for instance set its Title:
jsonObj.Some.Title = "NewTitle";
You won´t need any cast for this.
You can use a Slapper.AutoMapper functionality. Use MapDynamic() method for your needs.
public class Person
{
public int Id;
public string FirstName;
public string LastName;
}
[Test]
public void Can_Map_Matching_Field_Names_Using_Dynamic()
{
// Arrange
dynamic dynamicPerson = new ExpandoObject();
dynamicPerson.Id = 1;
dynamicPerson.FirstName = "Clark";
dynamicPerson.LastName = "Kent";
// Act
var person = Slapper.AutoMapper.MapDynamic<Person>( dynamicPerson ) as Person;
// Assert
Assert.NotNull( person );
Assert.That( person.Id == 1 );
Assert.That( person.FirstName == "Clark" );
Assert.That( person.LastName == "Kent" );
}
When you use as for casting, it Assigns null to the destination if the source is null or it is not convertible. So you cannot use it with value types. Where as this(jsonObj.Some = (SpecificObject1)jsonObj.Some) will throws InvalidCastException if either source is null or not convertible.
var #switch = new Dictionary<Type, Action> {
{ typeof(x), () => jsonObj.Some = (SpecificObject1)jsonObj.Some },
{ typeof(y), () => ......}
};
I have been looking for a way to pass an object as unknown type in c# without casting the object?
Essentially I am using reflection to grab the constructor parameters of a class, and I have variables that are casted as objects that I need to pass to the constructor, except I have found no way to dynamically cast the vars...
Code Sample:
public class bClass {
public bClass(string c) {
d = c;
}
}
object a = "asdfasdf";
bClass b = new bClass(a);
I have been able to get the type of variable bClass accepts in the constructor using
var obj = typeof(bClass).GetConstructors();
foreach(var nObj in obj) {
foreach(var param in nObj) {
string sAObjectType = param.ParameterType;
}
}
however, I am not sure how to cast 'a' to type sAObjectType, any ideas are greatly appreciated =]
Thank you!
What about using generics - then you don't have to worry to much about conversion etc.
public class bClass<T>
{
privat T d;
public bClass(T c)
{
d = c
}
}
Then things like below will work.
bClass b1 = new bClass( "1234" );
bClass b2 = new bClass( 12 );
...
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 First 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
}
}
}
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); }
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;
}
}
}
Once you get the reflected type, you can use Convert.ChangeType().
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.
How about setting the root value as a string and then carry it around as a string until you need to convert it to the target type?
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.
Type resultType = typeof(T);
IEnumerable<PropertyDescriptor> properties = TypeDescriptor.GetProperties(resultType).Cast<PropertyDescriptor>();
object instance = Activator.CreateInstance(resultType);
var objValue = "VALUE FOR HEADER";
var resultHeader = "HeaderName";
var prop = properties.Single(p => string.Equals(p.Name, resultHeader, StringComparison.InvariantCultureIgnoreCase));
var targetType = Nullable.GetUnderlyingType(prop.PropertyType) !=null Nullable.GetUnderlyingType(prop.PropertyType):prop.PropertyType;
objValue = Convert.ChangeType(objValue , targetType);
prop.SetValue(instance, objValue );
//return instance;
You want to access a property of another property of an object. All you really need is one method that repeats itself, i.e. the overload principle. I tried that and it worked.
public static object PropValue(object src, string firstPropName, string secoundPropName,string threedPropName)
{ // This will lead to Property of Property of the given InstanceProperty
var secoundProperty = PropValue(src, firstPropName, secoundPropName);
return PropValue(secoundProperty, threedPropName);
}
public static object PropValue(object src,string firstPropName, string secondPropName)
{ // This will lead to Property of an given InstanceProperty
var FirstProperty = PropValue(src, firstPropName);
return PropValue(FirstProperty, secondPropName);
}
public static object PropValue(object src, string propName)
{
// This will lead to the given InstanceProperty
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Is there a way to cast an instance of a class using a Type variable rather then an explicitly provided type?
For example in my method below "this" is a derived type of "Node". I want the method to repeatedly try to get a value from GetNodeIntrinsicProperty() after which if it get's a null value it should cast itself as it's base type and try again.
Basically, I want to call every implementation of GetNodeIntrinsicProperty() until I get a value.
public string GetIntrinsicProperty(String propertyKey)
{
//sets the original type value
Type currType = this.GetType();
Node thisNode = this;
String propertyValue;
while (currType is Node)
{
//casts thisNode as CurrType
thisNode = thisNode as currType;
/*The live above gives me the following error
*
* Error 20 The type or namespace name 'currType' could not be found
(are you missing a using directive or an assembly reference?) */
//trys to get the property with the current cast
//GetNodeIntrinsicProperty() is defined seperately in each type
propertyValue = thisNode.GetNodeIntrinsicProperty(propertyKey);
if (propertyValue != null)
{
return propertyValue;
}
//sets CurrType to its base type
currType = currType.BaseType;
}
return null;
}
Alright I took a step back and realized that what I'm really doing is trying to create a method that will return the value of a public property by passing the the property name. Rather then manually creating a relationship between a property in my class and a string that coincidentally has the same name I've figured that it's better to do that automatically.
So here's what I'm doing now, and it seems to work. In addition, I don't have to worry about two classes trying to define duplicate property keys because a derived class already can't have a duplicate property name to one in its base class unless there is an explicit abstract/override relationship.
public HashSet<string> GetIntrinsicPropertyKeys()
{
Type t = this.GetType();
PropertyInfo[] properties = t.GetProperties();
HashSet<string> keys = new HashSet<string>();
foreach (PropertyInfo pNfo in properties)
{
keys.Add(pNfo.Name);
}
return keys;
}
public string GetIntrinsicProperty(string propertyKey)
{
HashSet<string> allowableKeys = this.GetIntrinsicPropertyKeys();
String returnValue = null;
if (allowableKeys.Contains(propertyKey))
{
Type t = this.GetType();
PropertyInfo prop = t.GetProperty(propertyKey);
returnValue = (string)prop.GetValue(this, null);
}
return returnValue;
}
Ok, so first the answer to your question.
I'm assuming you have some structure like this:
public class Node
{
public string GetIntrinsicProperty(String propertyKey)
{
//sets the original type value
Type currType = this.GetType();
Node thisNode = this;
String propertyValue;
while (currType.IsSubclassOf(typeof(Node)))
{
MethodInfo mi = currType.GetMethod("GetIntrinsicProperty",BindingFlags.Instance | BindingFlags.Public,null,new Type[] {typeof(string)},null);
if (mi.DeclaringType != typeof(Node))
{
propertyValue = (string)mi.Invoke(this, new object[] { propertyKey });
if (propertyValue != null)
{
return propertyValue;
}
}
//sets CurrType to its base type
currType = currType.BaseType;
}
return null;
}
}
public class OtherNode : Node
{
new public string GetIntrinsicProperty(string propertyKey)
{
return "OtherNode says Hi!";
}
}
public class TestNode : Node
{
}
The implementation of GetIntrinsicProperty above will do what you're asking, but I would suggest that it's wrong.
You're forcing a child class to exactly replicate your signature and a developer to understand what you want. This is what virtual methods are for. If I'm understanding you correctly the proper way to do what you want is this:
public class Node
{
public virtual string GetIntrinsicProperty(String propertyKey)
{
switch(propertyKey)
{
case "NodeUnderstoodProp":
return "I know! Call on me!";
default:
return null;
}
}
}
public class OtherNode : Node
{
public override string GetIntrinsicProperty(string propertyKey)
{
switch (propertyKey)
{
case "OtherUnderstoodProp":
return "I'm the OtherNode, and I know better, call on me!";
default:
return base.GetIntrinsicProperty(propertyKey);
}
}
}
public class TestNode : Node
{
}
static void Main(string[] args)
{
Node node = new OtherNode();
var prop1 = node.GetIntrinsicProperty("NodeUnderstoodProp");
var prop2 = node.GetIntrinsicProperty("OtherUnderstoodProp");
var prop3 = node.GetIntrinsicProperty("PropTooHard!");
node = new TestNode();
prop1 = node.GetIntrinsicProperty("NodeUnderstoodProp");
prop2 = node.GetIntrinsicProperty("OtherUnderstoodProp");
prop3 = node.GetIntrinsicProperty("PropTooHard!");
}
The idea of virtual methods is that the type of your variable doesn't determine which implementation is called, but rather the run time type of the object determines it.
As far as I can tell, the situation you're describing is one where you are trying do your own dispatch to the implementation of a method on the runtime type of the object. Pretty much the definition of a virtual method.
If I didn't get the question right, please clarify. :)
I didn't fully understand what you're trying to do, but you can convert an object to a specific type using Convert.ChangeType(yourObject, yourType). It returns an object of type object so you still have to cast it manually. I don't know if that helps.