.NET Reflection set private property - c#

If you have a property defined like this:
private DateTime modifiedOn;
public DateTime ModifiedOn
{
get { return modifiedOn; }
}
How do you set it to a certain value with Reflection?
I've tried both:
dto.GetType().GetProperty("ModifiedOn").SetValue(dto, modifiedOn, null);
and
dto.GetType().GetProperty("modifiedOn").SetValue(dto, modifiedOn, null);
but without any success. Sorry if this is a stupid question but it's the first time I'm using Reflection with C#.NET.

That has no setter; you'd need:
public DateTime ModifiedOn
{
get { return modifiedOn; }
private set {modifiedOn = value;}
}
(you might have to use BindingFlags - I'll try in a moment)
Without a setter, you'd have to rely on patterns / field names (which is brittle), or parse the IL (very hard).
The following works fine:
using System;
class Test {
private DateTime modifiedOn;
public DateTime ModifiedOn {
get { return modifiedOn; }
private set { modifiedOn = value; }
}
}
static class Program {
static void Main() {
Test p = new Test();
typeof(Test).GetProperty("ModifiedOn").SetValue(
p, DateTime.Today, null);
Console.WriteLine(p.ModifiedOn);
}
}
It also works with an auto-implemented property:
public DateTime ModifiedOn { get; private set; }
(where relying on the field-name would break horribly)

You could try to set the backing field and not the property; you should use GetField() not GetProperty().

If your property doesn't have a setter, you can't call SetValue on it.

You need to set the field because you have no set property to set the property.
Additional the BindingFlags.NonPublic is needed for not public objects.
dto.GetType().
GetField("modifiedOn",
BindingFlags.NonPublic|BindingFlags.SetField|BindingFlags.Instance).
SetValue(dto, valueToSet);

If you have a private property with a setter then you can use this Extension method to set a value:
using System.Reflection;
public static class ObjectExtensions
{
public static void SetPrivateValue<T>(this T obj, string propertyName, object value)
{
var type = typeof(T);
type.GetTypeInfo().GetDeclaredProperty(propertyName).SetValue(obj, value, null);
}
}

One way to do it, and this is might be the most correct way, considering that set may or may not exist, is to use a specific accessor
var myc = new MyClass();
var pi = typeof(MyClass).GetProperty("Prop1", BindingFlags.NonPublic | BindingFlags.Instance);
if (pi.SetMethod != null) // check if you have 'set' accessor
pi.SetMethod.Invoke(myc, new object[]{ someValue });
else
{
// do nothing OR
throw new Exception("Attempted to set read-only property " + pi.Name);
}

Related

Get and Set String Property returning Empty Property

I'm trying to get and set a property using the following code.
But the when trying to print the property using Console,it returns an empty string.Why is the property not getting set?
using System;
public class Program
{
public static void Main()
{
myclass x=new myclass();
x.myproperty="test";
Console.WriteLine(x.myproperty);
}
class myclass{
string sample;
public string myproperty
{
get { return sample;}
set {sample=myproperty;}
}
}
}
In setter you should use value to assign new value to underlying field
use this instead
public string myproperty
{
get { return sample; }
set { sample = value; }
}
or in C#7
public string myproperty
{
get => sample;
set => sample = value;
}
Edit
As #bradbury9 mentioned, you can also use auto-implemented properties, of course this is the case if you don't want any other logic in getter and setter than just getting and setting the field, if this is the case you can use below snippet
public string myproperty { get; set; }
value keyword is important for setting the value. In Visual Studio you can use propfull + double tab to avoid such common mistakes. It will create full property through shortcuts.
Here is the solution
public static void Main()
{
myclass x = new myclass();
x.myproperty = "test";
Console.WriteLine(x.myproperty);
}
class myclass
{
string sample;
public string myproperty
{
get { return sample; }
set { sample = value; }
}
}
If you just want to return null instead of empty string. This works even when you deserialize your Json:
class myclass
{
string sample;
[JsonProperty("my_property")]
public string My_property
{
get { return sample; }
set { sample = string.IsNullOrEmpty(value) ? null : value; }
}
}

Set Object Property of Object Property by Reflection

I used this SO Question to retrieve a property of an object using reflection. The property I retrieved is another object that has a property called Value that I need to access. All of the potential objects that I retrieve using reflection derive from the same class EntityField and therefore all have a Value property. I saw this SO question that hinted at how I might be able to access the Value property, but I couldn't quite put together the correct code. How can I access the Value property on an object retrieved by reflection?
My Attempts
var parent = entity.GetType().GetProperty("Property");
parent.GetType().GetProperty("Value").SetValue(parent, newValue); // parent.GetType() is null
(parent as EntityField<T>).Value = newValue; // Not sure how to dynamically set T since it could be any system type
Main (Original Code)
private static void SetValues(JObject obj, EntityBase entity)
{
// entity.GetType().GetProperty("Property") returns an EntityField Object
// I need to set EntityField.Value = obj["Value"]
// Current code sets EntityField = obj["Value"] which throws an error
entity.GetType().GetProperty("Property").SetValue(entity, obj["Value"], null);
}
EntityField
public class EntityField<T> : EntityFieldBase
{
private Field _Field;
private T _Value;
public EntityField(Field field, T value){
this._Field = field;
this._Value = value;
}
public Field Field
{
get
{
return this._Field;
}
set
{
if (this._Field != value)
{
this._Field = value;
}
}
}
public T Value
{
get
{
return this._Value;
}
set
{
if (!EqualityComparer<T>.Default.Equals(this._Value, value))
{
this._Value = value;
this._IsDirty = true;
}
}
}
}
Try this:
entity.GetType().GetProperty("Value").SetValue(entity, obj["Value"], null);
You need to specify the name of the property in the GetProperty() method. I suspect there was no such property called 'Property' :)
Edit: After reading your comments try
entity.Property.GetType().GetProperty("Value").SetValue(entity, obj["Value"], null);
Tried the following in LinqPad and it worked...
class TestChild<T>
{
public T ChildProperty { get; set; }
}
class TestParent<T>
{
public TestChild<T> ParentProperty { get; set; }
}
void Main()
{
var instance = new TestParent<string>
{
ParentProperty = new TestChild<string>()
};
instance.GetType()
.GetProperty("ParentProperty")
.GetValue(instance)
.GetType()
.GetProperty("ChildProperty")
.SetValue(instance.ParentProperty, "Value");
Console.WriteLine(instance.ParentProperty.ChildProperty);
}

Enum value `Browsable(false)`

is there a way to make an enum value not browsable to combo box
or just, not to come back from Enum.GetValues() ??
public enum DomainTypes
{
[Browsable(true)]
Client = 1,
[Browsable(false)]
SecretClient = 2,
}
This is a generic method (based on another SO answer which I can't find) which you can call on any enum.
By the way, the Browsable attribute is already defined in System.ComponentModel.
For example:
ComboBox.DataSource = EnumList.Of<DomainTypes>();
...
public class EnumList
{
public static List<T> Of<T>()
{
return Enum.GetValues(typeof(T))
.Cast<T>()
.Where(x =>
{
BrowsableAttribute attribute = typeof(T)
.GetField(Enum.GetName(typeof(T), x))
.GetCustomAttributes(typeof(BrowsableAttribute),false)
.FirstOrDefault() as BrowsableAttribute;
return attribute == null || attribute.Browsable == true;
}
)
.ToList();
}
}
There is nothing already in place to do this for you with the Enum.GetValues() method. If you want to use attributes, you can create your own custom attribute and use it via reflection:
public class BrowsableAttribute : Attribute
{
public bool IsBrowsable { get; protected set; }
public BrowsableAttribute(bool isBrowsable)
{
this.IsBrowsable = isBrowsable;
}
}
public enum DomainTypes
{
[Browsable(true)]
Client = 1,
[Browsable(false)]
SecretClient = 2,
}
And then you can use reflection to check for custom attributes and generate a list of Enums based on the Browsable attribute.
It really can't be done in C# - a public enumeration exposes all members. Instead, consider using a wrapper class to hide/expose the items selectively. Maybe something like this:
public sealed class EnumWrapper
{
private int _value;
private string _name;
private EnumWrapper(int value, string name)
{
_value = value;
_name = name;
}
public override string ToString()
{
return _name;
}
// Allow visibility to only the items you want to
public static EnumWrapper Client = new EnumWrapper(0, "Client");
public static EnumWrapper AnotherClient= new EnumWrapper(1, "AnotherClient");
// The internal keyword makes it only visible internally
internal static readonly EnumWrapper SecretClient= new EnumWrapper(-1, "SecretClient");
}
Hope this helps. Good luck!

Dynamically identifying properties in C#

Is there a way to dynamically identify design time properties in C#? For example:
class MyClass
{
public string MyProperty1 { get; set; }
}
And then reference it something like this:
string myVar = "MyProperty1";
MyClass.myVar = "test";
If you want to set the value of a property at runtime and the name of the property is only known at runtime you need to use Reflection. Here's an example:
public class MyClass
{
public string MyProperty1 { get; set; }
}
class Program
{
static void Main()
{
// You need an instance of a class
// before being able to set property values
var myClass = new MyClass();
string propertyName = "MyProperty1";
// obtain the corresponding property info given a property name
var propertyInfo = myClass.GetType().GetProperty(propertyName);
// Before trying to set the value ensure that a property with the
// given name exists by checking for null
if (propertyInfo != null)
{
propertyInfo.SetValue(myClass, "test", null);
// At this point you've set the value of the MyProperty1 to test
// on the myClass instance
Console.WriteLine(myClass.MyProperty1);
}
}
}
how about simply implementing an indexer on your class
public class MyClass
{
public string MyProperty1 { get; set; }
public object this[string propName]
{
get
{
return GetType().GetProperty(propName).GetValue(this, null);
}
set
{
GetType().GetProperty(propName).SetValue(this, value, null);
}
}
}
and then you can do something very similar
var myClass = new MyClass();
string myVar = "MyProperty1";
myClass[myVar] = "test";
Yes, of course you can. You need to get a FieldInfo object relating to the property that you want to set.
var field = typeof(MyClass).GetField("MyProperty1");
then from that field info object, you can set the value of any instance of that class.
field.SetValue(myinstanceofmyclass, "test");
See MSDN: FieldInfo for other fun stuff you can do with reflection.

How do I reinitialize or reset the properties of a class?

I've created a class with properties that have default values. At some point in the object's lifetime, I'd like to "reset" the object's properties back to what they were when the object was instantiated. For example, let's say this was the class:
public class Truck {
public string Name = "Super Truck";
public int Tires = 4;
public Truck() { }
public void ResetTruck() {
// Do something here to "reset" the object
}
}
Then at some point, after the Name and Tires properties have been changed, the ResetTruck() method could be called and the properties would be reset back to "Super Truck" and 4, respectively.
What's the best way to reset the properties back to their initial hard-coded defaults?
You can have the initialization in a method instead of inlining with the declaration. Then have the constructor and reset method call the initialization method:
public class Truck {
public string Name;
public int Tires;
public Truck() {
Init();
}
public void ResetTruck() {
Init();
}
private void Init() {
Name = "Super Truck";
Tires = 4;
}
}
Another way is not to have a reset method at all. Just create a new instance.
Reflection is your friend. You could create a helper method to use Activator.CreateInstance() to set the default value of Value types and 'null' for reference types, but why bother when setting null on a PropertyInfo's SetValue will do the same.
Type type = this.GetType();
PropertyInfo[] properties = type.GetProperties();
for (int i = 0; i < properties.Length; ++i)
properties[i].SetValue(this, null); //trick that actually defaults value types too.
To extend this for your purpose, have private members:
//key - property name, value - what you want to assign
Dictionary<string, object> _propertyValues= new Dictionary<string, object>();
List<string> _ignorePropertiesToReset = new List<string>(){"foo", "bar"};
Set the values in your constructor:
public Truck() {
PropertyInfo[] properties = type.GetProperties();
//exclude properties you don't want to reset, put the rest in the dictionary
for (int i = 0; i < properties.Length; ++i){
if (!_ignorePropertiesToReset.Contains(properties[i].Name))
_propertyValues.Add(properties[i].Name, properties[i].GetValue(this));
}
}
Reset them later:
public void Reset() {
PropertyInfo[] properties = type.GetProperties();
for (int i = 0; i < properties.Length; ++i){
//if dictionary has property name, use it to set the property
properties[i].SetValue(this, _propertyValues.ContainsKey(properties[i].Name) ? _propertyValues[properties[i].Name] : null);
}
}
Unless creating the object is really expensive (and Reset isn't for some reason). I see no reason to implement a special reset method. Why don't you just create a new instance with a usable default state.
What is the purpose of reusing the instance?
If you did your initialization in a Reset method you can be good to go:
public class Truck {
public string Name;
public int Tires;
public Truck() {
ResetTruck();
}
public void ResetTruck() {
Name = "Super Truck";
Tires = 4;
}
}
Focusing of separation of concerns (like Brian mentioned in the comments), another alternative would be to add a TruckProperties type (you could even add your default values to its constructor):
public class TruckProperties
{
public string Name
{
get;
set;
}
public int Tires
{
get;
set;
}
public TruckProperties()
{
this.Name = "Super Truck";
this.Tires = 4;
}
public TruckProperties(string name, int tires)
{
this.Name = name;
this.Tires = tires;
}
}
Inside your Truck class, all you would do is manage an instance of the TruckProperties type, and let it do its reset.
public class Truck
{
private TruckProperties properties = new TruckProperties();
public Truck()
{
}
public string Name
{
get
{
return this.properties.Name;
}
set
{
this.properties.Name = value;
}
}
public int Tires
{
get
{
return this.properties.Tires;
}
set
{
this.properties.Tires = value;
}
}
public void ResetTruck()
{
this.properties = new TruckProperties();
}
}
This certainly may be a lot of (unwanted) overhead for such a simple class, but in a bigger/more complex project it could be advantageous.
That's the thing about "best" practices... a lot of times, there's no silver bullet, but only recommendations you must take with skepticism and your best judgement as to what applies to you in a particular case.
I solved a similar problem with reflection. You can use source.GetType().GetProperties() to get a list of all properties which belong to the object.
Although, this is not always a complete solution. If your object implements several interfaces, you will also get all those properties with your reflection call.
So I wrote this simple function which gives us more control of which properties we are interested in resetting.
public static void ClearProperties(object source, List<Type> InterfaceList = null, Type SearchType = null)
{
// Set Interfaces[] array size accordingly. (Will be size of our passed InterfaceList, or 1 if InterfaceList is not passed.)
Type[] Interfaces = new Type[InterfaceList == null ? 1 : InterfaceList.Count];
// If our InterfaceList was not set, get all public properties.
if (InterfaceList == null)
Interfaces[0] = source.GetType();
else // Otherwise, get only the public properties from our passed InterfaceList
for (int i = 0; i < InterfaceList.Count; i++)
Interfaces[i] = source.GetType().GetInterface(InterfaceList[i].Name);
IEnumerable<PropertyInfo> propertyList = Enumerable.Empty<PropertyInfo>();
foreach (Type face in Interfaces)
{
if (face != null)
{
// If our SearchType is null, just get all properties that are not already empty
if (SearchType == null)
propertyList = face.GetProperties().Where(prop => prop != null);
else // Otherwise, get all properties that match our SearchType
propertyList = face.GetProperties().Where(prop => prop.PropertyType == SearchType);
// Reset each property
foreach (var property in propertyList)
{
if (property.CanRead && property.CanWrite)
property.SetValue(source, null, new object[] { });
}
}
else
{
// Throw an error or a warning, depends how strict you want to be I guess.
Debug.Log("Warning: Passed interface does not belong to object.");
//throw new Exception("Warning: Passed interface does not belong to object.");
}
}
}
And it's use:
// Clears all properties in object
ClearProperties(Obj);
// Clears all properties in object from MyInterface1 & MyInterface2
ClearProperties(Obj, new List<Type>(){ typeof(MyInterface1), typeof(MyInterface2)});
// Clears all integer properties in object from MyInterface1 & MyInterface2
ClearProperties(Obj, new List<Type>(){ typeof(MyInterface1), typeof(MyInterface2)}, typeof(int));
// Clears all integer properties in object
ClearProperties(Obj,null,typeof(int));
You'd probably need to save the values off in private fields, so that they can be restored later. Maybe something like this:
public class Truck
{
private static const string defaultName = "Super Truck";
private static const int defaultTires = 4;
// Use properties for public members (not public fields)
public string Name { get; set; }
public int Tires { get; set; }
public Truck()
{
Name = defaultName;
Tires = defaultTires;
}
public void ResetTruck()
{
Name = defaultName;
Tires = defaultTires;
}
}
You're essentially looking for the State Design Pattern
If you want a specific past "state" of your object you can create a particular save point to return every time you want. This also let you have a diferent state to backup for everey instance that you create. If you class has many properties who are in constant change, this could be your solution.
public class Truck
{
private string _Name = "Super truck";
private int _Tires = 4;
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public int Tires
{
get { return _Tires; }
set { _Tires = value; }
}
private Truck SavePoint;
public static Truck CreateWithSavePoint(string Name, int Tires)
{
Truck obj = new Truck();
obj.Name = Name;
obj.Tires = Tires;
obj.Save();
return obj;
}
public Truck() { }
public void Save()
{
SavePoint = (Truck)this.MemberwiseClone();
}
public void ResetTruck()
{
Type type = this.GetType();
PropertyInfo[] properties = type.GetProperties();
for (int i = 0; i < properties.Count(); ++i)
properties[i].SetValue(this, properties[i].GetValue(SavePoint));
}
}
If you aren't using a Code Generator or a Designer that would conflict, another option is to go through C#'s TypeDescriptor stuff, which is similar to Reflection, but meant to add more meta information to a class than Reflection could.
using System.ComponentModel;
public class Truck {
// You can use the DefaultValue Attribute for simple primitive properites
[DefaultValue("Super Truck")]
public string Name { get; set; } = "Super Truck";
// You can use a Reset[PropertyName]() method for more complex properties
public int Tires { get; set; } = 4;
public void ResetTires() => Tires = 4;
public Truck() { }
public void ResetTruck() {
// Iterates through each property and tries to reset it
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(GetType())) {
if (prop.CanResetValue(this)) prop.ResetValue(this);
}
}
}
Note that ResetValue will also reset to a shadowed property if one exists. The priority of which option is selected is explained in the docs:
This method determines the value to reset the property to in the following order of precedence:
There is a shadowed property for this property.
There is a DefaultValueAttribute for this property.
There is a "ResetMyProperty" method that you have implemented, where "MyProperty" is the name of the property you pass to it.
You may represent an object state as a struct or record struct and then set the state to the default value in the Reset method like this:
public class Truck {
record struct State(string Name, int Tires);
private static readonly State _defaultState = new("Super Truck", 4);
private State _state = _defaultState;
public string Name => _state.Name;
public int Tires => _state.Tires;
public Truck() {}
public void ResetTruck() => _state = _defaultState;
}
It is probably the fastest way as well.
Also, a record struct will give you the trivial implementations of the ToString, Equals, GetHashCode.

Categories