get field by name - c#

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.

Related

Get Value from Override using Reflection

I want to get the value from a virtual property from a inherited class see my code below:
Base class:
public class TestBaseClass
{
public virtual int Index { get; }
}
Inherited class:
public class TestInheritedClass : TestBaseClass
{
public override int Index => 100; // I want to get this value using reflection
}
My Code:
static void Main(string[] args)
{
var assemblies = Assembly.LoadFile(args[0]);
foreach(var type in assembly.ExportedTypes)
{
if(type.IsSubclassOf(typeof(TestBaseClass))
{
foreach(var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
{
var value = prop.GetValue(typeof(int), null); // I expect to return 100 from override Index value
}
}
}
}
Did I missed something or did I made this all wrong? I'm trying to get the value 100 from the virtual property. Is there a way to get the value?
Is there a way to get the value?
Yes, there is a way.
Let's first see what you've done there:
prop.GetValue(typeof(int), null)
You're using this overload of PropertyInfo.GetValue. It expects the instance of the object from which to get the value as first parameter. Instead, you're passing typeof(int). That's not an instance of TestInheritedClass.
I will ignore the second parameter here, because we're not talking about an indexer.
You can read about that parameter in the documentation.
Instead you must create an instance of TestInheritedClass first:
var instance = Activator.CreateInstance(typeof(TestInheritedClass));
Then use it like this:
if (type.IsSubclassOf(typeof(TestBaseClass))
{
var instance = Activator.CreateInstance(type);
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
{
var value = prop.GetValue(instance);
}
}

How to pass a dynamic model as 'T' to a C# generic function

I have a generic function which is like below
private List<T> GetAll<T>()
{
var listOfTModels = // gets the list of T from the database.
return listOfTModels;
}
I need to pass the model ( T ) dynamically to this function based on a string which will be decided at runtime.
public void SomeFunction(string modelName)
{
// Call the above Get method with modelName parameter as the 'T'
var listOfModels = GetAll<something>(); //not sure what type this something should be "Type" or "string"
// Further Logic on listOfModels
}
How could this be done?
You will need to use reflection to get the method like so:
typeof(ClassWithGetAll).GetMethod("GetAll",
BindingFlags.Instance | BindingFlags.NonPublic);
This will return a method info which you will then use to create a generic method via MakeGenericMethod.
The only way to get a type from a string name AFAIK is with Type.GetType but you will need a AssemblyQualifiedName for that, so passing in a short/simplified name like string or int or anything like that will more than likely return null.
If you figure out how to either get the qualified name or how to search for the type, the last thing would be to invoke the MethodInfo returned from the MakeGenericMethod call, here is a example of how the code could look:
public void SomeFunction(string modelName)
{
// No idea what the class/struct in which the method "GetAll"
// is called, hence use this name
var instance = new ClassWithGetAll();
//Retrieves the info of "GetAll<T>"
MethodInfo method = typeof(ClassWithGetAll).GetMethod("GetAll",
BindingFlags.Instance | BindingFlags.NonPublic);
//Commented out as you will need to figure out how to get the
// assembly qualified name of the input model name, unless
// it is qualified.
//modelName = GetAssemblyQualifiedName(modelName);
Type modelType = Type.GetType(modelName);
//Creates a generic method: "GetAll<T>" => "GetAll<modelType>"
method = method.MakeGenericMethod(modelType);
//Invokes the newly created generic method in the specified
// instance with null parameters, which returns List<modelType>
object list = method.Invoke(instance, null);
}
I think inheritance would be the right way to solve your problem.
public class TBase
{
public int Prop { get; set; }
}
public class TChildOne : TBase
{
}
public class TChildTwo : TBase
{
}
public class GClass
{
private List<T> GetAll<T>() where T : TBase
{
var listOfTModels = // gets the list of T from the database.
return listOfTModels;
}
public void Main(string strType)
{
switch (strType)
{
case "TChildOne":
{
var child = GetAll<TChildOne>();
break;
}
case "TChildTwo":
{
var child = GetAll<TChildTwo>();
break;
}
default:
throw new Exception("type not found");
}
}
}

Is there a way to get the PropertyInfo from a accessor?

If you have a property's accessor(s), is there a way to retrieve the PropertyInfo to which they are attached to, without going through every property and seeing if the accessors match?
e.g.
//This example uses a sample from a obfuscated assembly
public class ObjectInfo
{
//the property which to get (laid out)
public int UQIOWVICXJ
{
[CompilerGenerated]
public int get_Id();
[CompilerGenerated]
private void HVKXLIREWQ(int num);
}
}
//retrieve method
public static PropertyInfo GetIdProp()
{
var get_accessor = typeof(ObjectInfo).GetMethod("get_Id", BindingFlags.Public | BindingFlags.Instance);
return //the property info via get_accessor;
}
The only way I see of doing this is by calling typeof(ObjectInfo).GetProperties(//All
Prop BindingFlags) and then, for each info in the result, check if the get method's name is equal to get_Id.

Why I can't assign dynamic data in constructor C#?

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

C# - Set Property of a Property with Reflection

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);

Categories

Resources