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
Related
Class Person {
int Id
string Name
string Address
// etc
}
instead of accessing it like Person.Id, Person.Name, Person.Address. I want to access it via index just like Person['Id'], Person['Name']. Is there any codegen or linq conversion for this.
You can use Json.NET's JObject class
Person p = new Person() { Id = 1, Address = "A", Name = "B" };
var obj = JObject.FromObject(p);
Console.WriteLine(obj["Id"]); //1
This is a pure C# implementation:
class Program
{
static void Main(string[] args)
{
Person person = new Person
{
Id = 1,
Name = "test",
Address = "tost"
};
Console.WriteLine(person["Id"]);
person["Id"] = 5;
Console.WriteLine(person["Id"]);
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public object this[string propertyName]
{
get
{
return this.GetType().GetProperty(propertyName).GetValue(this);
}
set
{
this.GetType().GetProperty(propertyName).SetValue(this, value);
}
}
}
Output:
1
5
Important note:
I would never recommend to use this in a production environment, if you want to use an handly implemented system, atleast you should handle types and properties extractions to avoid consuming more memory than needed and exceeding overheads.
Using reflection and indexers:
public class ExampleClass{
public object this[string name]
{
get
{
var properties = typeof(ExampleClass)
.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
if (property.Name == name && property.CanRead)
return property.GetValue(this, null);
}
throw new ArgumentException("Can't find property");
}
set {
return;
}
}
}
An indexer won't make data comparison any easier. I suspect the real question is how to handle data in C# the same way Python's DataFrames work. ADO.NET provides the DataTable class since .NET 1.0. It's meant more for database processing than data analysis, altough it does support operations like searching, merging and diffing.
For data anlysis, the new Microsoft.Data.Analysis package provides the DataFrame class.
That said, to read properties by name, you'll have to use Reflection, an expensive operation. One way to make this cheaper is to cache type and property descriptors. Instead of writing the code yourself though, you can use Marc Gravel's FastMember library that does just that. With this, you can create a TypeAccessor or ObjectAccessor type and read properties by name, eg :
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
Console.WriteLine(wrapped[propName]);
If you want to read from multiple objects, you'll need a TypeAccessor :
var accessor = TypeAccessor.Create(type);
string propName = // something known only at runtime
while( /* some loop of data */ )
{
accessor[obj, propName] = rowValue;
}
The library isn't that big. If you aren't allowed to use NuGet packages, you could copy the code into your project.
I am trying to create a function that can return a field from its object.
Here is what I have so far.
public class Base
{
public string thing = "Thing";
public T GetAttribute<T>(string _name)
{
return (T)typeof(T).GetProperty(_name).GetValue(this, null);
}
}
What I would ideally like is to call:
string thingy = GetAttribute<string>("thing");
but I have a feeling I got the wrong end of the stick when reading up on this because I keep getting null reference exceptions.
First thing - thing is a field, not a property.
Another thing is that you have to change parameter type to get it working:
public class Base {
public string thing = "Thing";
public T GetAttribute<T> ( string _name ) {
return (T)typeof(Base).GetField( _name ).GetValue (this, null);
}
}
BTW - you can get property/field value by referencing an instance:
var instance = new Base();
var value = instance.thing;
thing is a field not a property. You should use GetField method instead of GetProperty.
Another problem is you are looking in typeof(T). You should look for the field in typeof(Base).
The whole function should be changed to
public T GetAttribute<T>(string _name)
{
return (T)GetType().GetField(_name).GetValue(this);
}
If you want to have an extension method to get field value of a type you can use this
public static class Ex
{
public static TFieldType GetFieldValue<TFieldType, TObjectType>(this TObjectType obj, string fieldName)
{
var fieldInfo = obj.GetType().GetField(fieldName,
BindingFlags.Instance | BindingFlags.Static |
BindingFlags.Public | BindingFlags.NonPublic);
return (TFieldType)fieldInfo.GetValue(obj);
}
}
Use it like
var b = new Base();
Console.WriteLine(b.GetFieldValue<string, Base>("thing"));
Using BindingFlags will help you to get field value even if it is private or static field.
SO Community,
So I'm learning C# and am still trying to wrap my head around reflection. In particular trying to use it to access a property of a property on a class.
I've boiled down the basic task that I'm trying to accomplish below:
public enum SIGNAL_STATE { NOT_RETRIEVED = 0, RETRIEVING = 1, RETRIEVED = 2, FAILED = 3 }
public class MyObjectClass
{
public string MyString;
private SIGNAL_STATE _state = SIGNAL_STATE.NOT_RETRIEVED;
public SIGNAL_STATE State { get { return _state; } set { _state = value;} }
}
public class NeedToReflect
{
private MyObjectClass _myObject1 = new MyObjectClass();
private MyObjectClass _myObject2 = new MyObjectClass();
private MyObjectClass _myObject3 = new MyObjectClass();
public MyObjectClass MyObject1
{
get{return _myObject1;}
set{_myObject1 = value;}
}
public MyObjectClass MyObject2
{
get{return _myObject2;}
set{_myObject2 = value;}
}
public MyObjectClass MyObject3
{
get{return _myObject3;}
set{_myObject3 = value;}
}
public static void Main(string [] args){
NeedToReflect needToReflect = new NeedToReflect();
string fieldName;
for(int idx = 1; idx<=3; ++idx)
{
fieldName = String.Format("MyObject{0}",idx);
//TODO: set state of 'MyObject' values to SIGNAL_STATE.RETRIEVING
}
}
}
edit 1:
At Yair Nevet's suggestion I'm grabbing the FieldInfo from the applicable object like,
FieldInfo fieldInfo = needToReflect.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
But from there I get hung up on accessing and setting the right 'State' Field/Property on that member field
Solution (ie. here's what I plugged in on that TODO comment):
// Determine what binding flags will give us proper access to our member field
BindingFlags bindFlags = BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance;
// Get the field for that field
FieldInfo fieldInfo = needToReflect.GetType().GetField(fieldName, bindFlags);
// Pass in the containing object that we're reflecting on to get an instance of the member field
MyObjectClass myField = (MyObjectClass) fieldInfo.GetValue(needToReflect);
// We can now directly access and edit the value in question
myField.State = SIGNAL_STATE.RETRIEVING;
That does it. Thanks to Shlomi Borovitz for pointing me in the right direction.
Thanks!
The FieldInfo object which returned by GetField has property which called FieldInfo, which returns the type of that field.
And you can query it for that type's (the type of the field) properties/fields (and whatever you want) - and get/set them.
Remember that both GetType method (of any object), and the FieldInfo.FieldType property return Type object, that you can query in reflection.
object obj =...
var field = obj.GetType().GetField(fieldName,...);
field.FieldType.GetField(...
//etc... etc...
For each field, you can query the type and for each type, you can query the fields, and get/set them.
BTW, in C# 4.0 you can use the dynamic pseudo type (it used as a type when declaring dynamic variable, but it's not a real type), and then using that variable, while assuming which properties/fields/methods that variable would have in runtime (ie, using them like they are known in compile time although they don't).
This will not work for private members (and I can't warn you enough against calling private members in reflection), but for public members, this would make your code simple and readable, like you never used reflection (although, behind the scenes [in this case] reflection would be used).
You are trying to access a Property while the member is actually a private Field:
propertyName = String.Format("MyObject{0}",idx);
Use GetField method instead for that:
needToReflect.GetType().GetField(propertyName, BindingFlags.NonPublic |BindingFlags.GetField | BindingFlags.Instance);
Go through these steps...
1) Get the Type.
2) Have an instance of that type.
3) Get the PropertyInfo for the property.
4) Call "GetSetMethod" on the PropertyInfo object. It will return a MethodInfo object.
5) Invoke the MethodInfo object using the instance of the type and a value.
Given:
class ClassyMcClass
{
public int PropertyB { get; set; }
}
class MyClass
{
public ClassyMcClass PropertyA { get; set; }
}
The following code uses reflection on a MyClass object to set the int value of PropertyB in PropertyA to NewValue:
PropertyInfo propA = typeof(MyClass).GetProperty("PropertyA");
PropertyInfo probBofA = propA.PropertyType.GetProperty("PropertyB");
// Set property B of property A, where obj is of type MyClass
probBofA.SetValue(propA.GetValue(obj), NewValue, null);
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.
Is it possible? With reflection or any other way?
As other stated, if you need to do that, you're facing a design issue to begin with. Now, if you want to know if it's possible just for the sake of knowing, or if there's no other way on earth to do it, it's indeed possible, with the help of a very small helper library and an extension method.
Consider the following code:
class Person {
int age;
string name;
public int Age { get { return age; } }
public string Name { get { return name; } }
}
// ...
using Mono.Reflection;
using System.Reflection;
// ...
Person person = new Person (27, "jb");
PropertyInfo nameProperty = typeof (Person).GetProperty ("Name");
FieldInfo nameField = nameProperty.GetBackingField ();
nameField.SetValue (person, "jbe");
Using this code, you can get the backing field of a property with just the property, and assign a new value to the backing field. You can read more details about the implementation.
Also note that it works only for simple properties, such as:
public int Age { get { return age; } }
public string Name {
get { return name; }
set { name = value; }
}
public double Velocity { get; private set; }
If you have complex properties with custom code (which includes expression-bodied member like int Answer=> 42;), the backing field resolver will fail as there is no backing field in such case.
An alternate to Simon Mattes answer would be
Assuming you have:
public class MyClass
{
public int MyNumber {get;}
}
You could do this if its for test purpose:
var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(anIstanceOfMyClass, 3);
As a very dirty workaround for auto generated read only properties:
class MyTestClass
{
public string MyProperty { get; }
public MyTestClass( string MyProperty )
{
this.MyProperty = MyProperty;
}
}
You can modify the auto generated backing field in the following way:
MyTestClass MyClass = new MyTestClass( "Hello" );
FieldInfo MyWriteableField = MyClass.GetType().GetRuntimeFields().Where( a => Regex.IsMatch( a.Name, $"\\A<{nameof( MyClass.MyProperty )}>k__BackingField\\Z" ) ).FirstOrDefault();
MyWriteableField.SetValue( MyClass, "Another new value" );
PS: when you are using a .NET version < 4.6 you might have to change some of the code to work.
Enjoy!
it depends on the property. if it's a computed property - no, not unless you know what it's based on. if it's just an accessor to a private field, then you can try to modify the field.
in general, however, it's a very bad idea, as you likely have no knowledge of what side-effects this will cause.
PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance| BindingFlags.NonPublic);
//Remove the readonly property
isReadOnly.SetValue(param, false, null);
//.............put your code here.....
// Set readonly property
isReadOnly.SetValue(param, true, null);