Call Property based on a string of its name - c#

I need to call a public property of a class based on the string value of its name, as I won't know until run time what properties are required. I'm trying to use reflections unsuccessfully. The class looks like this:
class FieldCalculation
{
public string MyValue
{
get
{
return "Test Data";
}
}
}
I think access the value of the property should look something like this:
FieldCalculation myClass = new FieldCalculation();
string value = myClass.GetType().GetProperty("MyValue");
Any help would be appreciated.

You nearly had it. What you were doing was getting the property definition. You need to ask that property to get you the value, and you pass it the instance. This is the working code:
FieldCalculation myClass = new FieldCalculation();
string value = (string)myClass.GetType().GetProperty("MyValue").GetValue(myClass);

Related

Reflection not return value

I am trying to access field value using reflection, but cant make it work
public class Menssagens
{
public string Teste2;
public void Falar(string key, string id)
{
string json = File.ReadAllText(#"bin/" + id + ".json");
Menssagens dotNet = JsonConvert.DeserializeObject<Menssagens>(json);
Console.WriteLine(dotNet.Teste2); //Works fine
Console.WriteLine(typeof(Menssagens).GetField(key).GetValue(this));
//Dont works, returns nothing
}
You're accessing the property value on this. You never set it on this, so it returns null.
You probably want to access the value on the instance you created.
In fact, your method should be static.

How do I write a method that fills a property using the property's name?

Here is what I am looking at doing. Say I have a Class with a number of properties. I am trying to write a method that looks something like this
public static void GetNullableInt32(this DbDataReader reader, Type property)
{
property = reader.IsDBNull(reader.GetOrdinal(property.name))
? (int?)null
: reader.GetInt32(reader.GetOrdinal(property.name));
}
Where the property name is pulled from reflection, and the property is set in the method. I put in Type in the parameters as a placeholder for whatever type it needs to be. Then I would call it like
reader.GetNullableInt32(Class.Property1);
To set all the properties on a class from a database reader.
Is there an easy way to do this? Or is there a better structure where instead of having to enter the column name as a string it is pulled from the column name?
Edit
In response to a deleted comment asking why we don't just pass in the string name, the code used to look something like
Class item = new Class {
ContactRelationId = reader.IsDBNull(reader.GetOrdinal("ContactRelationId"))
? (int?)null
: reader.GetInt32(reader.GetOrdinal("ContactRelationId"))}
And the requirement passed down was that we should not store package procedures as strings.
you would need to send through the instance of the object that has the property, that is going to get that property set on it. if your class looked like:
public class MyClass
{
public int? MyInt { get; set; }
}
you'd have to send an instance to this method:
public static void GetNullableInt32(this DbDataReader reader, MyClass instance, string propName)
But why use reflection when you don't have to? It's slower, can often lead to bugs. Just do the assignment in the calling method:
public static void GetNullableInt32(this DbDataReader reader, string propName)
{
//...
}
//calling method
myClassInstance.MyInt = reader.GetNullableInt32(nameof(MyClass.MyInt));
all this assumes that your column names and property names are identical, as you seem to have specified they are.

How do I modify the value of an element in a list of type class containing a string and an integer?

I'm new to programming so this is probably a very elementary question. I created a list of a class which contains an integer and a string and I want to change the integer value of a specific index and/or the string name of a specific index. Here is my code:
class Sales
{
public Sales(string name, int quantitySold)
{
Name = name;
QuantitySold = quantitySold;
}
public string Name { get; set; }
public int QuantitySold { get; set; }
}
class Restaurant
{
private List<Sales> _quantityHistory = new List<Sales>();
public List<Sales> QuantityHistory
{
get { return _quantityHistory; }
}
}
If you want to change the property of an object it is fairly simple, let me walk you through it.
Sales mySale = new Sales()
This is going to be our object, at the moment it is empty as we have just initialized an empty variable, but what if we want to initialize it with a value? Well we can do this:
Sales mySale = new Sales()
{
Name = "SaleName",
QuantitySold = 5,
};
EDIT just realised your objects constructor is initializing variables that are passed in as parameters! You don't actually need to have those in the constructor if you have getters and setters and you use the method of creating a variable that I just did above this!
Basically we you first declare the property name that the object holds, followed by the value.
But what if we want to change it somewhere down the track? Well lets pretend that so far in our code we have done exactly like we did above, somewhere down the track somebody makes a purchase so we need to add one more to the QuantitySold of the object, well thats simple just do this:
mySale.QuantitySold = mySale.QuantitySold++;
Same as the name if we need to change it!
mySale.Name = "TheNewSaleName";
Basically we just use the variable name of the object we created, followed by a fullstop and the property name and we can change it however we want!
When using a list of objects you can simply search using the index of the list, for instance:
_quantityHistory[2].Name = "TheNewNameOfThe3rdObject";
Hope this helped buddy.

How do i access the constant field using instant reference using linq in C#?

I am having a model like below...
public class Class1
{
public const string Example = "Example";
public string Name { get; set:}
}
And one more model named as "Class2" in which "Class1" acts as virtual like below...
public class Class2
{
public int Id{get; set;}
public virtual Class1 class1obj {get; set;}
piblic int class1objId {get; set;}
}
Now I have one service method to get the values hold by model "Class2", mentioned below
GetClass<T>();
now, I planned to get data using below code:
var data = GetClass<Class2>(s => s.class1obj.Example == "Example1");
But, When i type the above code and i tried to access the constant like s.class1obj.Example it throws error and intellisense also shows only the "Name" property and did not shows the const Example declared in "Class1" ? Why, I am not able to access the constant field ? I am in learning process, please can any one help me on this...
You cannot access constants through an instance. You need to use the class name. For example:
var ex = Class1.Example;
An alternative would be to add an access property to your class:
public Class1
{
public const string Example = "Example";
public string ExampleConst { get { return Example; } }
}
Constant fields are implicitly static. This means that they belong not to an instance, but to a type. Therefore, to access the constant field you need to access not a class instance, but a type object, just as you would do with a static field or method. In your case, this means that you access Class1.Example and not class1obj.Example.
Example is a constant, think of it as a property of the class rather than of the object instance.
To access it you'd call
var val = Class1.Example;
and so
var data = GetClass<Class2>(s => Class1.Example == "Example1");
However this doesn't make sense to me (it will ALWAYS return true as it's a constant). I'm not entirely sure what you're trying to do in your lamba so it's difficult to advise any further...

How can I reach the "object" behind a property with reflection?

Is there a way to obtain the object behind a property by reflection?
I am trying to manage a dynamic setting of a property.
Example:
class Animal
{
public string Name {get;set;}
public string Family {get;set;}
}
class Zoo
{
public Animal Lion {get;set;}
public Animal Panda {get;set;}
}
class Test
{
public void SetLionNameWithReflection()
{
Zoo londonZoo = new Zoo();
Type zooType = typeof(Zoo);
PropertyInfo lionProperty = zooType.GetProperty("Lion");
// Now what to write here so that I can manage to set Lion's name to Kaspar?
// (to manage this by reflection Lion.Name = "Kaspar");
}
}
What lines should I add more at the commented part above?
Thanks!
I don't think you actually need to know the object behind a property. Use the SetValue method to set its value to "Kaspar":
EDIT - as per dlev's comment, this is how it should look like:
Lion kaspar = new Lion { Name="Kaspar" };
zooType.SetValue(londonZoo, kaspar, null);
A property doesn't necessarily have an object "behind" it.
It's defined by 2 functions, get and set, that can do whatever you want, and not necessarily return an object's value at all.
What you used is just a syntactic sugar to make it easier to make a property to wrap a member.
No you can't use reflection to definitively get the object behind an arbitrary property. Largely because it's not guaranteed that every property is bound to an object. It could just as easily be a calculated value.
public class Student {
public string m_firstName;
public string m_lastName;
public string FullName {
get { return String.Format("{0} {1}", m_firstName, m_lastName); }
}
}
In this case the property FullName produces a calculated value and has no single backing object.
The case you're listing though is for auto-properties. There is likely a way to dig through the fields and use a form of name matching to get the one backing a given auto-property. However such a solution would be fragile to versioning and certainly not recomended.
Can you add an overloaded constructor to your animal object, which will allow you to pass in the animal name, like this?:
londonZoo.GetProperty("Lion").SetValue(londonZoo, new Lion("Kaspar"), null);
First you need to create the lion:
var lion = Activator.CreateInstance(lionProperty.PropertyType);
Then you need to set the Lion property of the zoo:
lionProperty.SetValue(londonZoo, lion, null);
Then you can get the Name property of the lion:
PropertyInfo property = lion.GetType().GetProperty("Name",
BindingFlags.Public | BindingFlags.Instance);
Then you can set its name:
if (property != null && property.CanWrite)
{
property.SetValue(lion, "Kaspar", null);
}

Categories