Get object reference from PropertyInfo - c#

I have a little problem, below my code:
public class A
{
public string ObjectA { get; set; }
}
public void Run()
{
A a = new A();
a.ObjectA = "Test number 1";
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyInfo myPropertyInfo = a.GetType().GetProperty("ObjectA", flags);
object myNewObject = myPropertyInfo.GetValue(a);// Here should be reference
a.ObjectA = "Test number 2";//After this line value myNewObject continued "Test number 1"
}
So my value myNewObject must be in output "Test number 2". Is there any way? It is this at all possible?

Wrong!
You're getting the string rather than the instance of A using reflection.
Changing A.ObjectA doesn't change the string reference. Actually, you're setting a different string to the backing string class field by the ObjectA property...
Auto-properties are syntactic sugar to avoid explicitly declaring class fields to properties which perform nothing when getting or setting their values:
// For example:
public string Text { get; set; }
// is...
private string _text;
public string Text { get { return _text; } set { _text = value; } }
Now turn your code into regular one (no reflection):
A a = new A();
a.ObjectA = "hello world";
object myNewObject = a.ObjectA;
// Do you think now that myNewObject should change...? :)
a.ObjectA = "goodbye";
Is there any way? It is this at all possible?
No.
Maybe you can simulate this behavior using a Func<T>...
Func<object> myNewObjectGetter = () => myPropertyInfo.GetValue(a);
Now, whenever you call myNewObjectGetter() you're going to get the most fresh value of the whole property. BTW, this still doesn't address the impossible!

Is there any way?
No. You can't put a reference to a property into an object variable. Such a variable can only hold a normal value, such as the string you put into it.
That answers the question as asked. You can clarify what you want to achieve and maybe we can suggest a better way.

Probably there is no solution but I show some code
public class MyRows
{
public string Key { get; set; }
public int Id { get; set; }
public object Val { get; set; }
}
public abstract class BasicDTO
{
public int? Id { get; private set; }
public PropertyInfo[] PropertyDTO;
protected Type myType;
public BasicDTO()
{
Load();
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
PropertyDTO = myType.GetProperties(flags);
}
}
public class CustomerDTO : BasicDTO
{
public string Surname { get; set; }
public string Phone { get; set; }
public CustomerDTO() { }
protected override void Load()
{
myType = typeof(CustomerDTO);
}
}
Now my basic method
public void Run(BasicDTO dto)
{
PropertyInfo pi = dto.PropertyDTO.Where(x => x.Name == "Surname").SingleOrDefault();
MyRows mr = new MyRows();
mr.Val = pi.GetValue(dto);//Here I need reference
}
When I change CustomerDTO.Surname my value mr.Val it must also be changed.
As I wrote above, it is probably impossible, but maybe anybody have a idea.
BTW: Value mr.Val I use only for binding (WPF). So maybe you have any other suggestions, how solve problem. I will be grateful for your help

Related

C# Reflection GetField().GetValue()

Given the following:
List<T> someList;
Where T is a type of some class:
public class Class1
{
public int test1;
}
public class Class2
{
public int test2;
}
How would you use Reflection to extract the values of test1/test2 stored in each List item? (The field names are provided)
My Attempt:
print(someList[someIndex]
.GetType()
.GetField("test1")
.GetValue(someList) // this is the part I'm puzzled about. What kind of variable should i pass here?
The Error I'm getting:
"Object reference not set to an instance of an object", and according to microsoft docs the variable I should pass to GetValue is "The object whose field value will be returned." - which is what I'm doing.
Thanks for reading!
Add {get;set;} to your properties
public int test1 { get; set; }
var t = someList[0].GetType().GetProperty("test1").GetValue(someList[0], null);
I recommend you can use this method
public class Class1
{
public int test1 { get; set; }
public object this[string propertyName]
{
get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
}
}
var value = someList[0]["test1"];

how to iterate reference variable inside a class

I tried to use the code PropertyInfo[] but the code is not getting any attribute. Because the attribute inside class1 is just a reference variable
public readonly subClass1 sClass1;
public readonly subClass2 sClass2;
public readonly subClass3 sClass3;
public class1()//constructor
{
sClass1= new subClass1();
sbClass2= new subClass2();
sClass3= new subClass3();
}
My problem is, i can't access those 3 classes just by using PropertyInfo[]
but my i can access it using
Type type = typeof(class1);
FieldInfo[] fields = type.GetFields();
var i = 0;
foreach (var field in fields)
{
var f = field.GetType().GetFields();
i++;
}
But this code is not working as i want to work, they can get the class but i can't get the property of every subClass
What i want is something like this
var f = class1.sClass1;
my variable f will now hold the every property of a class.
I'm sorry if i can't explain it well. If you want to ask something, just comment below
by the way this is the inside code of every subClass
public string X{ get; set; }
public string Y{ get; set; }
public string Width { get; set; }
public string Length { get; set; }
You will have to do it recursively
void GetFields(Type type)
{
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Instance
| BindingFlags.Public | BindingFlags.NonPublic)) {
Console.WriteLine("{0} {1}", fieldInfo.FieldType.Name, fieldInfo.Name);
if (fieldInfo.FieldType.IsClass)
GetFields(fieldInfo.FieldType);
}
You have to use field.FieldType instead of using field.GetType()

Getting the value of a property of a class in a class

Ok so I have been up and down the internet looking for a solution to this question. I think my title is maybe no to informative so some background.
I have the following classes:
public class foo { public string Name { get; set; } }
public class foo1 { public string Name { get; set; } }
public class foo2 { public string Name { get; set; } }
public class foo3 { public string Name { get; set; } }
public class foo4 { public string Name { get; set; } }
public class foo5 { public string Name { get; set; } }
public class goo
{
public string Desc { get; set; }
public foo f { get; set; }
public foo1 f1 { get; set; }
public foo2 f2 { get; set; }
public foo3 f3 { get; set; }
public foo4 f4 { get; set; }
}
So now my question, Using Reflection, how can I get to the value of foo.Name when only having a reference to goo.
The normal Reflection code is:
goo g = new goo();
PropertyInfo pInfo = g.GetType().GetProperty("Name");
string Name = (string)pInfo.GetValue(g, null);
So the above code is how you get a property from the goo class. But now how do you get the value of foo.Desc?
I tried the following which doesn't work:
goo g = new goo();
PropertyInfo pInfo = g.GetType().GetProperty("f");
PropertyInfo pInfo2 = pInfo.PropertyType.GetProperty("Desc");
string Name = (string)pInfo2.GetValue(pInfo.PropertyType, null);
Unfortunately I get a Mismatched object error which I can understand because I am trying to use the property type and not the actual instance of the foo class. I also tried to fins a way to instantiate an object from the propertyinfo but if there is a way then it eludes me. I could do something like this:
goo g = new goo();
PropertyInfo propInfo = g.GetType().GetProperty("f");
object tmp;
propInfo.SetValue(g, Convert.ChangeType(new foo(), propInfo.PropertyType), null);
tmp = g.f;
This works but besides having to hard code the class, that is creating a new instance and therefore of now use to me.
As I say I have been up and down looking for a solution. Everything I have found is basically variants on the "get a value of a property of a class" theme but nothing about going another level deeper.
Can anyone help? Is this even possible because I would really like to stay away from hard coding.
EDIT: I have edited the class to more accurately represent what I am working with. Based on the comments below, I am getting the names of the foo instances from a database and that is why I am using Reflection or want to use Reflection instead of hard coding 30+ switch statements.
EDIT: Also I don't know before runtime which foo classes will be populated with data. Also each foo class is different. Unlike my example where each foo class has a string property, in my project each class has a different design which mirrors the database.
EDIT: So Ulugbek Umirov gave the answer. I just didn't see it immediately. Below my implementation so as to maybe help others in the future.
foreach (PropertyInfo pInfo in _standard.GetType().GetProperties())
{
if (_fullDataModel.ClassDefinitions.Contains(pInfo.Name))
{
PropertyInfo _std_pinfo = _standard.GetType().GetProperty(pInfo.Name);
object g = _std_pinfo.GetValue(_standard, null);
PropertyInfo props = g.GetType().GetProperty("showMe");
bool showMe = (bool)props.GetValue(g, null);
if (showMe)
{
string tblName = _fullDataModel.ClassDefinitions[pInfo.Name]. PropertyGroupDefinitions.Where(p => p.TransactionsTable != true).First().Token;
// Use tblName to build up a dataset
}
}
}
This does exactly what I wanted.
Thank you.
Given your current code you can do the following:
goo g = new goo();
g.f = new foo { Name = "Hello" };
PropertyInfo pInfo = g.GetType().GetProperty("f");
object f = pInfo.GetValue(g);
PropertyInfo pInfo2 = f.GetType().GetProperty("Name");
string name = (string)pInfo2.GetValue(f);
You can set arbitrary property as well:
goo g = new goo();
PropertyInfo pInfo = g.GetType().GetProperty("f");
object f = Activator.CreateInstance(pInfo.PropertyType);
PropertyInfo pInfo2 = f.GetType().GetProperty("Name");
pInfo2.SetValue(f, "Hello");
pInfo.SetValue(g, f);

.net 4.0 Reflection convert object to specific type

My problem is quite simple
Suppose I have those class:
public class A
{
public Collection<B> B { get; set; }
public Collection<C> C { get; set; }
}
public class B
{
public int IntB { get; set; }
}
public class C
{
public string StringC { get; set; }
}
And I write a function:
public void GetValue(string fieldName){
A a = new A();
PropertyInfo infor = typeof(A).GetProperty(fieldName);
object obj = infor.GetValue(a,null);
}
My question is how can I turn obj to corresponding Collection, in this case is Collection<B> or Collection<C>, depending in fieldName value
Thank in advance
You can cast it:
var collection = (Collection<B>)(infor.GetValue(a,null));
EDIT:
if you use LINQ on the resulting collections, you may want to use OfType (link: http://msdn.microsoft.com/en-us/library/bb360913.aspx) and/or Cast (link: http://msdn.microsoft.com/en-us/library/bb341406.aspx)
Like
var collection = getCollection(a,null));
collection.OfType<B>.Select(b => b.IntB)....
You can't have a statically typed object in your method when you determine the property that will be called at runtime. But the runtime time of obj is of the actual type of your property.

Why does GetFields() not return anything?

I am trying to retrieve the public properties of an object but it is returning nothing. Can you tell me what I'm doing wrong.
public class AdHocCallReportViewModel : ReportViewModel
{
public string OperatorForCustEquipID { get; set; }
public string OperatorForPriorityID { get; set; }
public string OperatorForCallTypeID { get; set; }
public string OperatorForStatusID { get; set; }
}
public UpdateReportParameters(AdHocCallReportViewModel rvm)
{
var type = rvm.GetType();
foreach (var f in type.GetFields().Where(f => f.IsPublic))
{
Console.WriteLine(f.Name);
Console.WriteLine(f.GetValue(rvm).ToString());
}
}
When stepping through the code, it skips over the foreach loop because GetFields returns zero items.
You haven't got public fields. They are properties. So try type.GetProperties() instead.
You are trying to get fields, you should try to call GetProperties()
Pass BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public to get all instance fields.
On second thought, I'm seeing that you are explicitly filtering for public fields. The class does not have any public fields. The fields that are automatically generated by the compiler as the backing store for the properties are private.

Categories

Resources