In PHP I can use a variable variable to access a class property dynamically like so:
class foo
{
public $bar = 'test';
}
$a = 'bar';
$obj = new foo;
echo $obj->$a; // output 'test'
How can I do something like this in C#?
Assuming:
public class Foo
{
public String bar { get; set; }
}
// instance that you want the value from
var instance = new Foo { bar = "baz" };
// name of property you care about
String propName = "bar";
You can use:
// Use Reflection (ProperyInfo) to reference the property
PropertyInfo pi = instance.GetType()
.GetProperty(propName);
// then use GetValue to access it (and cast as necessary)
String valueOfBar = (String)pi.GetValue(instance);
End result:
Console.WriteLine(valueOfBar); // "baz"
to make things easier:
public static class PropertyExtensions
{
public static Object ValueOfProperty(this Object instance, String propertyName)
{
PropertyInfo propertyInfo = instance.GetType().GetProperty(propertyName);
if (propertyInfo != null)
{
return propertyInfo.GetValue(instance);
}
return null;
}
public static Object ValueOfProperty<T>(this Object instance, String propertyName)
{
return (T)instance.ValueOfProperty(propertyName);
}
}
And given the same assumptions as above:
// cast it yourself:
Console.WriteLine((String)instance.ValueOfProperty(propName)); // "baz"
// use generic argument to cast it for you:
Console.WriteLine(instance.ValueOfProperty<String>(propName)); // "baz"
You wouldn't do something like that, variable variables are not supported in C#. You could use reflection to get a property value, but that's a whole other beast since you will be losing strong-typing etc. Quite simply it comes down to why do you want to do this? You shouldn't need to, in most cases as there are generally better alternatives than runtime resolution of values.
What you can do instead is use a string based dictionary (ie. Dictionary<string, string>) to index your values by a key.
You can then do something like this:
class Foo
{
public Dictionary<string, string> values = new Dictionary<string, string>();
public Foo()
{
values["foo"] = "test";
}
}
var test = "foo";
var foo = new Foo();
Console.WriteLine(foo.values[test]);
Related
I am trying to solve the following problem. We have an object of arbitrary structure and an array of strings representing field names. This array is a path that is used to retrieve specific fields using reflection. Then there is a value that should be stored in the final field. For example consider the following class hierarchy:
class A {
public int i;
}
class B {
public A a;
}
class C {
public B b;
}
class D {
public C c;
}
Let's say we get the input somehow:
object obj = GetObject(); // e.g. returns object of type D
List<string> path = GetPathToStore(); // e.g. returns {"c", "b", "a", "i"}
object value = GetValueToBeStored(); // e.g. returns 42
I wrote the following loop:
foreach (string fieldName in path) {
FileInfo fieldInfo = obj.GetType().GetField(fieldName);
obj = fieldInfo.GetValue(obj);
}
Then would be nice to have something like this:
obj = value;
But this will only change the reference and not the actual field in the object. In C++ I would write:
*obj = value;
but how to do this in C#?
I also need to support an edge case when the path is empty in which case the root object itself needs to be assigned a different value.
EDIT: My code actually uses more complex approach to retrieve members. Entries in the path are not necessarily field names, they could also be a property name, index in an array or List, key in a Dictionary etc. Therefore a class wrapping it would be complex. I am looking for a simpler solution.
Maybe something like this:
object obj = new D { c = new C { b = new B { a = new A { i = 1 } } } };
List<string> path = new List<string> { "c", "b", "a", "i" };
object value = 42;
FieldInfo fieldInfo = null;
object prevObj = null;
object obj2 = obj;
for (int i = 0; i < path.Count; i++)
{
string fieldName = path[i];
fieldInfo = obj2.GetType().GetField(fieldName);
if (i == path.Count - 1) prevObj = obj2;
obj2 = fieldInfo.GetValue(obj2);
}
if (fieldInfo != null)
{
fieldInfo.SetValue(prevObj, value);
}
Console.WriteLine(((D)obj).c.b.a.i == (int) value);
You can add the extra layer of indirection in a managed language, just as you can through pointer manipulation. In general, this is usually done through the use of a new class, since you can think of a class in general as a pointer to an object.
public class FieldWrapper
{
private object obj;
private FieldInfo field;
public FieldWrapper(object obj, FieldInfo field)
{
this.obj = obj;
this.field = field;
}
public object Value
{
get
{
return field.GetValue(obj);
}
set
{
field.SetValue(obj, value);
}
}
}
By holding onto the object instance and the FieldInfo object you can get and set the value of that object. This allows you to pass an instance of FieldWrapper around and just get/set the property and have it affect the underlying field of the object supplied in the constructor.
If you need something more generic you can rely on closures:
public class Wrapper
{
private Func<object> getter;
private Action<object> setter;
public Wrapper(Func<object> getter, Action<object> setter)
{
this.getter = getter;
this.setter = setter;
}
public object Value
{
get
{ return getter(); }
set
{ setter(value); }
}
}
Then to use it you could do something like this:
Wrapper pointer = new Wrapper(()=> fieldInfo.GetValue(obj)
, value => fieldInfo.SetValue(obj, value));
It takes a bit more work to create the objects, but has the same effect.
Another approach that you could take is to create a FieldWrapper, a PropertyWrapper, a DictionaryWrapper, etc. and have them all implement anIWrapperinterface that exposes aValue` so that once you create the wrapper you don't care what the underlying implementation is. That's a bit more work up front to create the wrapper for each type of object, but ends up taking less time to create each instance of the wrapped type.
I'm not sure if I understand your question correctly, but I think you want:
var fieldInfo = obj.GetType().GetField(fieldName);
fieldInfo.SetValue(obj, newValue);
EDIT: To support properties as well as fields, try:
foreach(var memberInfo in obj.GetType().GetMember(memberName))
{
if(memberInfo is FieldInfo)
{
((FieldInfo)memberInfo).SetValue(obj, newValue);
}
else if(memberInfo is PropertyInfo)
{
((PropertyInfo)memberInfo).SetValue(obj, newValue);
}
// etc ...
}
Not sure about how exactly you want to deal with indices, though. You CAN pass indices for indexed properties to PropertyInfo.SetValue().
Can I cast ExpandoObject to anonymous type ?
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
// Here I'm populating the expandoObj with same property names/types in anonymoustype(anoObj)
// Now, how to convert this ExpandoObject to anonymoustype ?
var newObj = (typeof(anoObj)expandoObj); // This doesn't work
Added Later
// This is my entity
public class Customer
{
#region Public Properties
[ColumnAttribute(Name = "IdColumn")]
public string Id { get; set; }
[ColumnAttribute(Name = "NameColumn")]
public string Name { get; set; }
[ColumnAttribute(Name = "AddressColumn")]
public string Address { get; set; }
[ColumnAttribute(Name = "EmailColumn")]
public string Email { get; set; }
[ColumnAttribute(Name = "MobileColumn")]
public string Mobile { get; set; }
#endregion
}
// -------------------------------------------------------------------------------------
public class LookupService<TEntitySource>
{
public LookupService ()
{
}
public LookupShowable<TEntitySource, TSelection> Select<TSelection>(Expression<Func<TEntitySource, TSelection>> expression)
{
var lookupShowable = new LookupShowable<TEntitySource, TSelection>();
return lookupShowable;
}
}
public class LookupShowable<TEntitySource,TSelection>
{
public LookupShowable()
{
}
public LookupExecutable<TEntitySource, TSelection, TShow> Show<TShow>(Expression<Func<TEntitySource, TShow>> expression)
{
var lookupExecutable = new LookupExecutable<TEntitySource,TSelection,TShow>();
return lookupExecutable;
}
}
public class LookupExecutable<TEntitySource, TSelection, TShow>
{
public TSelection Execute()
{
// Here I want to create a new instance of TSelection and populate values from database and return it.
}
}
//--------------------------------------------------------------------------------------
// This is How I want to call this from front end...
var lookupService = new LookupService<Customer>();
var lookupSelection = lookupService.Select(C => new { C.Id, C.Name, C.Mobile }).Show(C => new { C.Id, C.Name}).Execute();
string sID = lookupSelection.Id;
string sName = lookupSelection.Name;
string sMobile = lookupSelection.Mobile;
Dont think about this middle part.. Purpose of it is another one...
My problem is in Execute() method in LookupExecutable class. I dont know how to create a new instance of TSelection type and assign values to it. This TSelection type is always an anonymous type..
EDIT: I think this question is a prime example of the XY problem. The correct solution doesn't need to concern itself with ExpandoObject or anonymous types, and it would be most likely wrong if it did.
You're looking at it the wrong way. You don't need to create an instance of an anonymous object, you need to invoke the code that is passed to you in an expression (which may or may not be creating an anonymous object).
If you can create an instance of TEntitySource, then that's simple: Compile() the Expression that you got in Select() and then invoke it for each instance of TEntitySource.
If you can't create TEntitySource, you could still do it by rewriting the Expression (using ExpressionVisitor), so that its input is not TEntitySource, but some type you have. But that would require some work from you.
Original answer:
No, that won't work. That's simply not how casting or anonymous types work in C#.
You can't cast between any two types and expect it to work. Either the object you're casting needs to be the type you're casting to, or one of the two types needs to specify a matching cast operator.
The fact that the target type is an anonymous type doesn't change anything (except that you can't even try to cast to an anonymous type directly, because you can't name it; the way you're using typeof() is wrong).
The fact that the source type is dynamic changes things a bit. But only in that the search for the cast operator is done at runtime, not at compile time, and you can even create the cast operator at runtime (see DynamicObject.TryCast()). But that's it, it doesn't add any “magical” cast operators.
The only way I can imagine something like this working would be if you used a variant of “cast by example” and reflection:
public T Convert<T>(ExpandoObject source, T example)
where T : class
{
IDictionary<string, object> dict = source;
var ctor = example.GetType().GetConstructors().Single();
var parameters = ctor.GetParameters();
var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();
return (T)ctor.Invoke(parameterValues);
}
You could then use it something like this:
var expando = new ExpandoObject();
dynamic dynamicExpando = expando;
dynamicExpando.Foo = "SomeString";
dynamicExpando.Bar = 156;
var result = Convert(expando, new { Foo = "", Bar = 1 });
Note that you can't actually invoke Convert() dynamically (by passing it dynamicExpando), because that would mean it would return dynamic too.
Use JavaScriptSerializer to convert the ExpandoObject to any Type as follows:
.....
dynamic myExpandoObject = new ExpandoObject();
var result = ConvertDynamic<myType>(myExpandoObject);
.....
public T ConvertDynamic<T>(IDictionary<string, object> dictionary)
{
var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var obj = jsSerializer.ConvertToType<T>(dictionary);
return obj;
}
This should do the job.
here you have an object made from an ExpandoObject
var anoObj = new { name = "testName", email = "testEmail" };
dynamic expandoObj = new System.Dynamic.ExpandoObject();
object newObj = expandoObj;
But beware, dynamic objects are very very expensive in resource matters, and what you are asking for does not seem to have any sense. A good aproach for what you are asking in the comments supposing you have to deal with dynamic objects and you want to do something with them:
dynamic expando = new System.Dynamic.ExpandoObject();
var myObj = new Dictionary<string, object>();
myObj["myProperty"] = expando.myProperty;
Any dynamyc object is easily casted to a <string, object> typed Dicionary.
Hope that helps!
i've some classes and want to access their properties using index or something like
ClassObject[0] or better will be ClassObject["PropName"]
instead of this
ClassObj.PropName.
Thanks
You need indexers:
http://msdn.microsoft.com/en-us/library/aa288465(v=vs.71).aspx
public class MyClass
{
private Dictionary<string, object> _innerDictionary = new Dictionary<string, object>();
public object this[string key]
{
get { return _innerDictionary[key]; }
set { _innerDictionary[key] = value; }
}
}
// Usage
MyClass c = new MyClass();
c["Something"] = new object();
This is notepad coding, so take it with a pinch of salt, however the indexer syntax is correct.
If you want to use this so you can dynamically access properties, then your indexer could use Reflection to take the key name as a property name.
Alternatively, look into dynamic objects, specifically the ExpandoObject, which can be cast to an IDictionary in order to access members based on literal string names.
You can do something like this, a pseudocode:
public class MyClass
{
public object this[string PropertyName]
{
get
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
return pi.GetValue(this, null); //not indexed property!
}
set
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
pi.SetValue(this, value, null); //not indexed property!
}
}
}
and after use it like
MyClass cl = new MyClass();
cl["MyClassProperty"] = "cool";
Note that this is not complete solution, as you need to "play" with BindingFlags during reflection access if you want to have non public properties/fields, static ones and so on.
public string this[int index]
{
get
{ ... }
set
{ ... }
}
This will give you an indexed property. You can set any parameter you wish.
I'm not sure what you mean here, but I'll say that you have to make ClassObject some sort of IEnumirable type, like List<> or Dictionary<> to use it the way to aim for here.
I have the following code, should be easy to follow through
public class Foo
{
public void FooHasAMethod()
{
Console.WriteLine("it is me, foo!!!");
}
}
public class Bar
{
public Foo FooProperty { get; set; }
}
public class FooBar
{
public static void Main()
{
Bar bar = new Bar{ FooProperty = new Foo() };
CallPropertyByName(bar, "Foo");
}
public static void CallPropertyByName(Bar bar, string propertyName)
{
PropertyInfo pi = bar.GetType().GetProperty(propertyName + "Property");
object fooObj = pi.GetValue(bar, null);
((Foo)fooObj).FooHasAMethod(); // this works
/* but I want to use
* ((Type.GetType(propertyName))fooObj).FooHasAMethod(); This line needs fix
* which doesnt work
* Is there a way to type cast using a string name of a object?
* */
}
}
If you're using .NET 4, it's actually really easy =D
dynamic obj = bar;
obj.FooProperty.FooHasAMethod();
However, if you just want to cast the result to some other type, you can do that at runtime with the Convert.ChangeType method:
object someBoxedType = new Foo();
Bar myDesiredType = Convert.ChangeType(typeof(Bar), someBoxedType) as Bar;
Now, this one has a strong link to the actual types Foo and Bar. However, you can genericize the method to get what you want:
public T GetObjectAs<T>(object source, T destinationType)
where T: class
{
return Convert.ChangeType(typeof(T), source) as T;
}
Then, you can invoke like so:
Bar x = GetObjectAs(someBoxedType, new Bar());
SomeTypeYouWant x = GetObjectAs(someBoxedType, Activator.CreateInstance(typeof("SomeTypeYouWant")));
Using the activator, you can at runtime create any type you want. And the generic method is tricked by inference into attempting a convert from your boxedType to the runtime type.
In addition, if you want to just call a method on some dynamic property value, then the best practice (imo), would be to simply cast it as some desired object.
ISomething propValue = obj.GetProperty("FooPropery").GetValue(obj, null) as ISomething;
if(propValue != null)
propValue.FooHasAMethod();
It is not possible to cast to a type not known at compile-time.
Have a look at the .NET 4.0 dynamic type.
Type fooObjType = fooObj.GetType();
MethodInfo method = fooObjType.GetMethod("FooHasAMethod");
method.Invoke(fooObj, new object[0]);
There's no way to cast by using string. But you can use dynamic, or MethodInfo with invoke
I have a class with a static factory method on it. I want to call the factory to retrieve an instance of the class, and then do additional initialization, preferablly via c# object initializer syntax :
MyClass instance = MyClass.FactoryCreate()
{
someProperty = someValue;
}
vs
MyClass instance = MyClass.FactoryCreate();
instance.someProperty = someValue;
No. Alternatively you could accept a lambda as an argument, which also gives you full control in which part of the "creation" process will be called. This way you can call it like:
MyClass instance = MyClass.FactoryCreate(c=>
{
c.SomeProperty = something;
c.AnotherProperty = somethingElse;
});
The create would look similar to:
public static MyClass FactoryCreate(Action<MyClass> initalizer)
{
MyClass myClass = new MyClass();
//do stuff
initializer( myClass );
//do more stuff
return myClass;
}
Another option is to return a builder instead (with an implicit cast operator to MyClass). Which you would call like:
MyClass instance = MyClass.FactoryCreate()
.WithSomeProperty(something)
.WithAnotherProperty(somethingElse);
Check this for the builder
Both of these versions are checked at compile time and have full intellisense support.
A third option that requires a default constructor:
//used like:
var data = MyClass.FactoryCreate(() => new Data
{
Desc = "something",
Id = 1
});
//Implemented as:
public static MyClass FactoryCreate(Expression<Func<MyClass>> initializer)
{
var myclass = new MyClass();
ApplyInitializer(myclass, (MemberInitExpression)initializer.Body);
return myclass ;
}
//using this:
static void ApplyInitializer(object instance, MemberInitExpression initalizer)
{
foreach (var bind in initalizer.Bindings.Cast<MemberAssignment>())
{
var prop = (PropertyInfo)bind.Member;
var value = ((ConstantExpression)bind.Expression).Value;
prop.SetValue(instance, value, null);
}
}
Its a middle between checked at compile time and not checked. It does need some work, as it is forcing constant expression on the assignments. I think that anything else are variations of the approaches already in the answers. Remember that you can also use the normal assignments, consider if you really need any of this.
Yes. You can use object initializer for already created instance with the following trick. You should create a simple object wrapper:
public struct ObjectIniter<TObject>
{
public ObjectIniter(TObject obj)
{
Obj = obj;
}
public TObject Obj { get; }
}
And now you can use it like this to initialize your objects:
new ObjectIniter<MyClass>(existingInstance)
{
Obj =
{
//Object initializer of MyClass:
Property1 = value1,
Property2 = value2,
//...
}
};
P.S. Related discussion in dotnet repository:
https://github.com/dotnet/csharplang/issues/803
You can use an extension method such as the following:
namespace Utility.Extensions
{
public static class Generic
{
/// <summary>
/// Initialize instance.
/// </summary>
public static T Initialize<T>(this T instance, Action<T> initializer)
{
initializer(instance);
return instance;
}
}
}
You would call it as follows:
using Utility.Extensions;
// ...
var result = MyClass.FactoryCreate()
.Initialize(x =>
{
x.someProperty = someValue;
x.someProperty2 = someValue2;
});
+1 on "No".
Here's an alternative to the anonymous object way:
var instance = MyClass.FactoryCreate(
SomeProperty => "Some value",
OtherProperty => "Other value");
In this case FactoryCreate() would be something like:
public static MyClass FactoryCreate(params Func<object, object>[] initializers)
{
var result = new MyClass();
foreach (var init in initializers)
{
var name = init.Method.GetParameters()[0].Name;
var value = init(null);
typeof(MyClass)
.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
.SetValue(result, value, null);
}
return result;
}
No, the object initializer can only be used on a call to "new" with the constructor. One option might be to add some additional args to your factory method, to set those values at object creation inside the factory.
MyClass instance = MyClass.FactoryCreate(int someValue, string otherValue);
Like everyone said, no.
A lambda as an argument has already been suggested.
A more elegant approach would be to accept an anonymous and set the properties according to the object. i.e.
MyClass instance = MyClass.FactoryCreate(new {
SomeProperty = someValue,
OtherProperty = otherValue
});
That would be much slower though, since the object would have to be reflected on for all the properties.
No, that's something you can only do 'inline'. All the factory function can do for you is to return a reference.