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);
}
Related
Say I have this class with a few members, for example (this is a contrived example, I'd rather no have a discussion about the intricacies of the real-life design. I really just want to convey the general idea here.):
public class Address
{
public Guid Id { get; set; }
public Guid? HouseId { get; set; }
public Guid? FlatId { get; set; }
public Guid? SomeOtherBuildingTypeId { get; set;
}
Now as it happens there exist 3 methods to create an Address:
public void CreateAddressForHouse();
public void CreateAddressForFlat();
public void CreateAddressForSomeOtherBuildingType();
Under the surface this group of methods does the exact same thing, bar setting a different Id property in the Address class. This is causing quite some code duplication in the real life application and I want to rewrite this to something more general.
In my mind I can pass the name of the required property and its value to a CreateAddress function, in something like a Func. But I'm seriously lacking in this respect, where to start? What .NET stuff can I use out of the box? Or what specific keywords should I look for?
You can use a MemberExpression:
public void CreateAddress(Expression<Func<Address, Guid?>> member)
{
// Get the property from the expression
var propertyInfo = GetPropertyInfo(this, member);
// Create a new address
var guid = Guid.NewGuid();
// Assign it to the property of this instance
propertyInfo.SetValue(this, guid);
}
Then you call the method like this, using a lambda a => a.PropertyName:
var address = new Address();
address.CreateAddress(a => a.HouseId);
Console.WriteLine(address.HouseId);
See Retrieving Property name from lambda expression for the implementation of GetPropertyInfo. It gets the PropertyInfo of the member specified in the lambda expression (and checks that it is indeed a property), which you can use to set the property in the CreateAddress method.
Apart from that, #Corak's suggestion is a valid one. Maybe you shouldn't use a property per address type, but use a Dictionary<AddressType, Guid?> property. That may or may not be viable depending on the class design and its intended usage.
You can use expression trees to simplify your problem:
public class AddressService
{
public Address CreateAddress(Expression<Func<Address, Guid?>> idPropertySelector)
{
// So you get the property info to later set it using reflection
MemberExpression propertyExpr = (MemberExpression)idPropertySelector.Body;
PropertyInfo property = (PropertyInfo)propertyExpr.Member;
// Then you create an instance of address...
Address address = new Address();
// and you set the property using reflection:
property.SetValue(address, (Guid?)Guid.NewGuid());
return address;
}
}
Now, who knows where in your code, this will work:
AddressService service = new AddressService();
Address address = service.CreateAddress(a => a.FlatId);
Guid? flatId = address.FlatId; // This will be already assigned!
You can add a property BuildingType BuildingType being a value of the enum BuildingType { House, Flat, SomeOtherBuildingType, YetAnotherThing } as suggested by Corak.
To make it simpler, you can create a parameterized constructor in Address class:
public Address(Guid? id,BuildingType type)
{
switch(type)
{
case BuildingType.House:
HouseId=id;
break;
case BuildingType.Flat:
FlatId=id;
break;
case BuildingType.SomeOtherBuildingType:
SomeOtherBuildingTypeId =id;
break;
default:
break;
}
}
This way it will be easier to extend.
Also, you need not to have so many methods. Only one CreateAddress() can be used to generate address of multiple types.
If I declare the following in my class:
private int? MyID = null;
And then attempt to access it via reflection, it won't be able to find it. What I mean by that is, the below will set gProp to null:
gType = refObj.GetType();
gProp = gType.GetProperty(PropertyName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
However, it will work fine if I instead declare it as:
private int? MyID { get; set; }
This isn't at all surprising to me as I already knew this to be the case. However, I wanted to confirm; is there anyway to make the first declaration work with reflection, or do I have provide a Getter/Setter in order for reflection to work?
Thanks!
It is a field, not a property, so it won't be returned by GetProperty. You need to use GetField method.
You need the GetField method (instead of GetProperty) for Fields.
Type.GetFields Method
Searches for the specified field, using the specified binding constraints.
Sample
// your instance
MyObject instance = new MyObject();
// get type information
Type myType = typeof(MyObject);
// get field information
FieldInfo fieldInfo = myType.GetField("MyID");
// set some value
fieldInfo.SetValue(instance, 123);
// get field value
var value = fieldInfo.GetValue(instance);
// value is 123
More Information
MSDN - Type.GetField Method (String, BindingFlags)
MSDN - SetField Method (String, BindingFlags, Object)
There is a difference between
private int? MyID = null;
and
private int? MyID { get; set; }
The first is a field, and the second is a property.
You should use the Type.GetField() method when trying to find a field via reflection.
You should create a property for accessing the variables in the class. So you manually create a property like
private int? MyID { get { return _myID;} }
The below code works, since it is Auto property in c#
private int? MyID { get; set; }
Refer http://msdn.microsoft.com/en-us/library/bb384054.aspx
My logic states the first is a simple variable, the second is a property, because it has the get/set, so for "GetProperty" to work, it needs to be a property. If you wanted a variable, you need the GetField
I've come across a strange behaviour in .NET/Reflection and cannot find any solution/explanation for this:
class A
{
public virtual string TestString { get; set; }
}
class B : A
{
public override string TestString
{
get { return "x"; }
}
}
Since properties are just pairs of functions (get_PropName(), set_PropName()) overriding only the "get" part should leave the "set" part as it is in the base class. And this is just what happens if you try to instanciate class B and assign a value to TestString, it uses the implementation of class A.
But what happens if I look at the instantiated object of class B in reflection is this:
PropertyInfo propInfo = b.GetType().GetProperty("TestString");
propInfo.CanRead ---> true
propInfo.CanWrite ---> false(!)
And if I try to invoke the setter from reflection with:
propInfo.SetValue("test", b, null);
I'll even get an ArgumentException with the following message:
Property set method not found.
Is this as expected? Because I don't seem to find a combination of BindingFlags for the GetProperty() method that returns me the property with a working get/set pair from reflection.
EDIT:
I would expect that behaviour if I'd use BindingFlags.DeclaredOnly on GetProperties() but the default (BindingFlags.Default) takes inherited members into account and the setter of TestString clearly is inherited!
Here's a workaround:
typeof(B).GetProperty("TestString")
.GetAccessors() // { B.get_TestString() }
.First() // B.get_TestString()
.GetBaseDefinition() // A.get_TestString()
.DeclaringType // typeof(A)
.GetProperty("TestString") // A.TestString: CanRead and CanWrite
This approach should be reasonably robust. You will need to be more careful with this (BindingFlags) if you're looking for non-public accessor(s).
EDIT:
Note that this approach is different from "hardcoding" typeof(A).GetProperty("TestString") or typeof(B).BaseType.GetProperty("TestString") because it finds the actual, original type that declares the property in question. Since it isn't possible (not in C# at least) for a derived type to add new accessors to an overridden property, the property-declaration on this "original" type should contain all the relevant accessors.
You're not overwritting a method, you're overwritting a property definition
The default definition of the property includes Get/Set methods, and your new definition only includes a Get method, so it makes sense that your overwritten property only has Get available, not Set
Edit
If you run something like Reflector on this, you'll see that
class A
{
public virtual string TestString { get; set; }
}
class B : A
{
public override string TestString
{
get { return "x"; }
}
}
compiles into something like that looks like
internal class A
{
// Fields
[CompilerGenerated]
private string <TestString>k__BackingField;
// Methods
public A();
// Properties
public virtual string TestString { [CompilerGenerated] get; [CompilerGenerated] set; }
}
internal class B : A
{
// Methods
public B();
// Properties
public override string TestString { get; }
}
When you set the value in code, you are actually calling something like B.base.set_TestValue. When you reflect something, you are trying to find B.set_TestValue, which doesn't exist.
While true that you cannot overwrite a property, you can overwrite a property definition (providing it doesn't conflict with the base property definition). Since your question was originally tagged with WPF, I was thinking of DependencyProperties at the time, which are actually property definitions, and not properties in the sense that you might be thinking of.
What is the best practice to create pre-initialized class. For example
Chip chip = new Atmega8();
I would like to have its properties already defined like:
chip.Name = "Atmega8 AVR Chip";
and so on.
How to achieve it in C#?
Should I use readonly public properties or property with private set?
Have your constructor initialize the values:
class Atmega8 {
public Atmega8 ()
{
Name = "Atmega8 AVR Chip";
}
public string Name { get; set; }
}
If you intend Name to be the same for all instances, it might make sense to declare it abstract in the base class and override the getter:
abstract class Chip {
public abstract string Name { get; }
}
class Atmega8 : Chip {
public override string Name {
get { return "Atmega8 AVR Chip"; }
}
}
Because we haven't defined a set method, the value cannot be changed, much like a readonly variable except it isn't even stored anywhere and just returned on each call.
If you want the compiler to enforce that nothing can change the value of the field once initialized, then set it up as a read-only field, and populate it in the constructor of the class (or simply initialize it when you declare it; this doesn't work so well with inheritance though). If you don't care as long as nothing OUTSIDE the object can change it (meaning you will trust your own coding discipline to ensure it doesn't change internally), a get-only property with a backing field, or an auto-property with a private setter, are your bets.
IF you absitively posolutely DO NOT WANT the value to change for a particular class, EVER, then I would make it a get-only property returning either a string literal or a constant. I would recommend using the constant over the literal, as you can put the constants into their own static class which you can then use separately from each Chip class.
HOWEVER, there's a quirk of constants you should know. A constant value in .NET is stored in the manifest of not only the assembly containing the declaring code, but in every assembly that references the declaring assembly. Each assembly's code them uses the value from its own manifest. So, if the constant value EVER changes, any assembly that references the declaring assembly must be recompiled to update those assemblies' manifests with the new value. Otherwise, the constant will only have its new value when used from within the declaring assembly. For this reason, labeling a variable as constant should not be done lightly. Personally, my opinion is if the constant isn't some value on which the continued existence and functioning of the universe depends, like pi, e, the speed of light in a vacuum, Plank's Constant, Avogadro's Number, etc, then it isn't "constant". Anything else, like communication code ordinals, CAN change, even if doing so would break compatibility with every previous version of your program.
Depends what you want to accomplish.
It looks like you never want the value of Name to change. One approach would be to declare Name as abstract in Chip, and implement Name in each child class to return a constant string value.
abstract class Chip
{
public abstract string Name { get; }
}
class Amiga8 : Chip
{
public override string Name { get { return "Atmega8 AVR Chip"; } }
}
class Program
{
static void Main(string[] args)
{
Chip chip = new Amiga8();
Console.WriteLine(chip.Name);
}
}
In the constructor of the Atmega8 class you can set a property to something. Ie:
public Atmega8() {
Name = "Atmega8 AVR Chip";
}
If you do not want that to be changed in runtime you could mark the property as readonly ( only assignable through a constructor of declarative ).
private readonly string _Name = string.Empty;
public string Name {
get { return _name; }
}
public Atmega8() {
_Name = "Atmega8 AVR Chip";
}
Value of property cannot change -> Read-only public property.
Value of property can change -> Property with private set
If you don't want it to change, make the Name property a const or readonly on the Atmega8 class. Private set still allows the Name to change internally.
You're saying that you want the class to be populated at the same time it's initialized? Just populate the object in the constructor, like so:
class Test
{
public Test()
{
this.Name = "Hello World";
}
//if you need to pass information into the constructor:
public Test(string testName)
{
this.Name = testName;
}
}
Then, you can do this to initialize it:
Test test = new Test(); //default name of Hello World!
OR
Test test = new Test("Bingo!");
1) I'm still quite new to programming and have read a bit about getters and setters. But I really don't understand why they are used.. Could anyone explain it, or point me to an article? (The ones I read were not really understandable for me...)
2) In my current project I have a class where I declare and initialize an array of structs. I now need to access the array from another class, but it gives me the error: An object reference is required to access non-static member 'BaseCharacter.Attributes'.
I figures this could mean I need to use getters and setters? But how does this work for arrays?
Thanks in advance!
Simon.
EDIT: 2nd question got solved, which brings me to something else. When I want to use some class in another one, I'm making a new instance of the class, right? And this means I get the original values?
But that's not what I want.
The second class is used to generate the UI, and needs the values I'm keeping in the first class.
At some point I will implement save files (XML or even on a server in later stage). Can I then just get the values from those files?
For the getters and setters (the things that use them are called Properties) it's just a convenient and nice-looking way to make people think they're using a variable, but to do some computation whenever the variable is updated or accessed. For instance:
BankAccount.Interest
looks better than
BankAccount.GetInterest()
Even though you can calculate the interest at the time it is requested in both cases.
They are also used to make a variable be able to be accessed from outside the class, but changeable only from within the class with this technique:
public double Interest {
get;
private set;
}
For an example of a setter being used, if you've ever used Windows Forms and updated a control's Height or Width property, you're using a setter. While it looks like you're using a normal instance variable like c.Height = 400, you're really letting c update it's position by redrawing at a new place. So setters notify you exactly when a variable is changed, so your class can update other things base on the new value.
Yet another application of Properties is that you can check the value people try to set the property to. For instance, if you want to maintain an interest rate for each bank account but you don't want to allow negative numbers or numbers over 50, you just use a setter:
private int _interestRate = someDefault;
public int InterestRate {
get { return _interestRate; }
set {
if (value < 0 || value > 50)
throw new SomeException(); // or just don't update _interestRate
_interestRate = value;
}
}
This way people can't set public values to invalid values.
For your second question, you can do one of two things depending on what you're trying to do.
One: You can make that member static. That means that just one of them exists for the entire class instead of one per instance of the class. Then you can access it by ClassName.MemberName.
You can do that this way:
// inside the BaseCharacter class definition:
public static SomeStruct[] Attributes = new SomeStruct[size];
// then to use it somewhere else in your code, do something with
BaseCharacter.Attributes[index]
Two: You have to make an instance of the class and access the array through that. This means that each object will have its own seperate array.
You'd do that like this:
BaseCharacter bc = new BaseCharacter();
// use bc.Attributes
The second one is probably what you'll want to do, since you probably will want to modify each character's attributes seperately from all the other characters.
Actually the error you mention is not related to the getters and setters concept, it's because after creating your class you need to create an object before using its members; think of the class as a template for a document and the object as the document
you are most likely doing something like this:
var someVar = BaseCharacter.Attributes;
When you should be doing something like this:
var someVar = new BaseCharacter();
var someOtherVar = someVar.Attributes;
And about why the getters and setters, Seth Carnegie's Answer covers it nicely.
If you are new to Object Oriented Programming, you may be missing an important concept, that is about encapsulation.
Fields (attributes) of a class should be accessed only from within the class (or it's inherited classes). That is, if we have a class person, only with a name, you can do
public class Person
{
public string Name;
}
So anywhere in your program, you will be able to access it by doing:
Person person = new Person();
person.Name = "Andre";
This works, but it's not encapsulated. In some languages like C++ or Java, it was done like this:
public class Person
{
private string _name;
public string setName(string newName)
{
this._name = newName;
}
public string getName()
{
return this._name;
}
}
Person person = new Person();
person.setName("Andre");
This makes our _name attribute encapsulated, it can only be retrieved by it's get and set methods (that is, by the interface of the class).
C# makes this easier, allowing getters and setters:
public class Person
{
private string name;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
}
Person person = new Person();
person.Name = "Andre";
This is very much like the second example (Java/C++ way), but you treat Name as property, instead of methods, and leaving our name property encapsulated
1) They might seem optional but they allow you more control over code:
You're able to intercept new values and avoid them being set (e.g. to exclude pointless values). Also you're able to fire custom events in case a property is changed or updated (just like the WinForms controls do).
private string name;
public string Name
{
get
{
// running additional code, e.g. here I avoid returning 'null' for a name not set
if(name == null)
return "(Unknown)";
return name;
}
set
{
// checking incoming values, e.g. here I avoid setting an empty name
name = value != null && value.Length > 0 ? name : null;
// running more/additional code, e.g. here I raise an event
if(OnNameChange)
OnNameChange();
}
}
2) Without knowing the code it's hard to tell you the exact reason, but if you'd like to access some member variable or property you have to either create an object of that class or make the variable static (e.g. shared between all instances of the object):
class MyClass
{
public static int someNumber = 55;
public int thisNumber;
}
// ...
int someothervar = MyClass.someNumber; // access the static member variable
MyClass mc = new MyClass(); // create an object of the class
int yetanothervar = mc.thisNumber; // access the member variable