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.
Related
I'm a PHP Developer...
I need to do a class that can be created and fill of dynamic way, similar to this in PHP.
class Person{
private $name;
private $age;
function __construct($params = array()){
foreach ($this as $key => $val) {
$this -> $key = (isset($params[$key])) ? $params[$key] : "";
}
}
function getName(){
return $this->name;
}
function getAge(){
return $this->age;
}
function setName($value){
$this->name = $value;
}
function setAge($value){
$this->age = $value;
}
}
I read about the reflection in C#, but I don't find the correct way to do.
This is my C# code
public class Person
{
private String _name { get { return _name; } set { _name = value; } }
private int _age { get { return _age; } set { _age = value; } }
public Person()
{
}
public Person(Hashtable _data)
{
PropertyInfo[] propertyInfos;
propertyInfos = typeof(Person).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var propInfo in propertyInfos)
{
typeof(Person).GetProperty(propInfo.Name).SetValue(this, _data[propInfo.Name]);
}
}
}
In runtime I get an Exception
Object reference not set to an instance of an object.
The typeof(Person) I try to change it to this.getType() and I get the same.
I hope that can help me.
You are grabbing all properties on the object and then looking them up in the hashtable. You likely want the reverse--all objects in the hashtable set to properties on the object. Otherwise you'll get an exception when you don't specify every single member.
As Alexei points out, the NullReferenceException is due to the second call to GetProperties only returning public properties when no BindingFlags are supplied. Since there are no public properties, you get an exception.
Because C# is strongly typed, you run into a number of issues you don't have in PHP. These include setting a value with an object of a type that doesn't match or convert to the property type, entries in your data parameter that don't exist as properties, etc. I've done my best to document the gotchas I see below.
Here is what the Person class would look like (I've cleaned up some of the style and used classes to make it feel more like a C# class):
public class Person
{
private string name { get; set; }
private int age { get; set; }
public Person()
{
}
public Person(IDictionary<string,object> data)
{
foreach (var value in data)
{
// The following line will be case sensitive. Do you need to standardize the case of the input dictionary before getting the property?
PropertyInfo property = typeof(Person).GetProperty(value.Key, BindingFlags.Instance | BindingFlags.NonPublic);
if (property != null)
{
property.SetValue(this, value.Value); // You are allowing any old object to be set here, so be prepared for conversion and casting exceptions
}
else
{
// How do you want to handle entries that don't map to properties? Ignore?
}
}
}
}
And here is an example of usage:
static void Main(string[] args)
{
var person = new Person(new Dictionary<string,object>() {{"name" ,"Mike"}, {"age", 32}});
}
You should stay away from using var if you're new to the language, it only complicates things.
The propInfo in your foreach-loop already is a PropertyInfo, so you don't need to find it again:
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] propertyInfos = typeof(Person).GetProperties(flags);
foreach (PropertyInfo propInfo in propertyInfos)
{
propInfo.SetValue(this, _data[propInfo.Name]);
}
The NullReferenceException is probably caused by the following part of your original code:
typeof(Person).GetProperty(propInfo.Name)...
Since no BindingFlags are provided to the GetProperty() this time, it looks for public instance properties, and when no such property is found, it returns null (that, or _data is null to begin with).
As others have pointed out, your properties currently will cause StackOverflowExceptions. Try changing them to:
private String _name { get; set; }
private int _age { get; set; }
I am wondering why you would want to do this. There may be better, more idiomatic C#, designs to achieve the behavior you want. But we can't know that because there is no additional contextual information mentioned in the question.
So I will simply try to answer your question. The version below takes your code, using auto properties, and a simple dictionary lookup for the initialization of its members from the supplied dictionary. Also note that this does not require any reflection, because there is nothing dynamic about the members of this class.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(IDictionary<string, object> data)
{
// What to do if the map does not contain "Name" or "Age" ?
// Right now: initialize to default value.
Name = TryLookup<string>(data, "Name", null);
Age = TryLookup<int>(data, "Age", default(int));
// What to do if the map contains other items that do not
// map to a member variable?
}
private static T TryLookup<T>(IDictionary<string, object> data, string key, T defaultValue)
{
return data.ContainsKey(key) ? (T)data[key] : defaultValue;
}
}
In case you actually really really badly need a dynamic type as opposed to a statically defined type with fixed member properties, you could use an ExpandoObject or alternatively (but this is far from trivial) build a dynamic type using an AssemblyBuilder with a TypeBuilder
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]);
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().
I want to create a property of a class, and set the name of that property using a variable value.
E.g.
string resultValue = "stack";
MyClass myclass = new MyClass();
myclass.resultValue = "overflow";
Now here in this case, stack is the property name and "overflow" is the value of the stack property.
Please tell how is it possible.
Thanks in advance.
You could use Reflection. For example:
string name = "stack";
string value = "overflow";
PropertyInfo pi = typeof(MyClass).GetProperty(name);
MyClass instance = new MyClass();
pi.SetValue(instance, value, null);
// at this stage instance.stack equals to "overflow"
This obviously assumes that MyClass has a public property stack with a public setter:
public class MyClass
{
public string stack { get; set; }
}
You should use Reflection for this
MyClass myclass = new MyClass();
Type type = typeof(MyClass);
PropertyInfo property = type.GetProperty("stack");
property.SetValue(myclass, "overflow", null);
I think that the Dynamic Source Code Generation and Compilation section on MSDN should contain the information you need.
The .NET Framework includes a mechanism called the Code Document
Object Model (CodeDOM) that enables developers of programs that emit
source code to generate source code in multiple programming languages
at run time, based on a single model that represents the code to
render.
I think that you could also get this done using Reflection.
Maybe you should take a look at DynamicObject. With this you can create properties at runtime by simply assigning a value. An example can also be found at the MSDN article.
Have at look at Mark Gravell's FastMember
It allows you to set properties in a dynamic manner.
// obj could be static or DLR
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
FastMember Blog Post
I can't imagine why you want to generate property on your class, but consider other ways. E.g. using Dictionary:
class MyClass
{
Dictionary<string, object> _values = new Dictionary<string, object>();
public object this[string name]
{
get
{
if (!_values.ContainsKey(name))
throw new ArgumentException(name);
return _values[name];
}
set
{
if (!_values.ContainsKey(name))
{
_values.Add(name, value);
return;
}
_values[name] = value;
}
}
}
Usage:
MyClass myClass = new MyClass();
myClass["stack"] = "overflow";
Console.WriteLine(myClass["stack"]);
As far as I know, is this not possible. You can try using a dictionary.
I want to implement a custom collection that contains instances of my class.
This is my class, a bit simplified here.
public class Property : IComparable<Property>
{
public string Name;
public string Value;
public string Group;
public string Id;
...
...
public int CompareTo(Property other)
{
return Name.CompareTo(other.Name);
}
}
I am adding instances of Property to a List collection
Public List<Property> properties;
I can iterate through properties or access a specific property through the index position.
I want to however be able to access the property by its Name such that
var myColor = properties["Color"].Value;
and I do not have an efficient way to do this. I assume that properties should be written as a custom list collection class to achieve this. Does anyone have a code sample I can look at?
Thanks for the help.
Easiest methods were already mentioned, but I see two:
Method 1
Convert to dictionary and lookup there.
var props = properties.ToDictionary( x => x.Name );
Property prop = props["some name"];
Method 2
Create your own collection type which would support indexing
by your arbitrary type.
public class PropertyCollection : List<Property>
{
public Property this[string name]
{
get
{
foreach (Property prop in this)
{
if (prop.Name == name)
return prop;
}
return null;
}
}
}
and use this collection instead
PropertyCollection col = new PropertyCollection();
col.Add(new Property(...));
Property prop = col["some name"];
You can use a Dictionary:
Dictionary<string, Property> properties = new Dictionary<string, Property>();
//you add it like that:
properties[prop.Name] = prop;
//then access it like that:
var myColor = properties["Color"];
Use a Dictionary<string,Property> for this purpose. The key will be the property name and the value will be the Property instance itself.