C# Reflection, how to get property instance within class to setvalue - c#

I'd like to reset the properties of a class back to their default values within a method of the class. My class is instantiated once (is actually a ViewModel in an MVVM framework) and I don't want to destroy and recreate the entire ViewModel, just clear many of the properties. The below code is what I have. The only thing I am missing is how to get the first parameter of the SetValue method - I know it is an instance of the property I am setting, but I cannot seem to figure out how to access that. I get error: "Object does not match target type".
public class myViewModel
{
...
...
public void ClearFields()
{
Type type = typeof(myViewModel);
PropertyInfo[] pi = type.GetProperties();
foreach (var pinfo in pi)
{
object[] attributes = pinfo.GetCustomAttributes(typeof(DefaultValueAttribute), false);
if (attributes.Length > 0)
{
DefaultValueAttribute def = attributes[0] as DefaultValueAttribute;
pinfo.SetValue(?, def.Value, null);
}
}
}
...
...
}

You should pass an instance of myViewModel, in your case use this to reference the current instance:
public class myViewModel
{
...
...
public void ClearFields()
{
Type type = typeof(myViewModel);
PropertyInfo[] pi = type.GetProperties();
foreach (var pinfo in pi)
{
object[] attributes = pinfo.GetCustomAttributes(typeof(DefaultValueAttribute), false);
if (attributes.Length > 0)
{
DefaultValueAttribute def = attributes[0] as DefaultValueAttribute;
pinfo.SetValue(this, def.Value, null);
}
}
}
...
...
}

You should put this as a first parameter. See MSDN for reference:
objType: System.Object
The object whose property value will be set.

Related

Get properties of properties

So, I am interested in getting all properties of a class via reflection ... and all properties of class-type properties (recursively).
I managed to get the first level of properties via reflections with a code like this:
foreach (var property in Target.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var foobar = Factory.GetDealer(Target, property.Name);
}
and in the factory:
public static BaseDealer GetDealer(Object obj, string property)
{
var prop = obj.GetType().GetProperty(property);
if (prop == null)
{
return null;
}
if (prop.PropertyType.IsPrimitive)
{
return GetPrimitivDealer(obj, property, Type.GetTypeCode(prop.PropertyType));
}
if (prop.PropertyType.IsClass)
{
return new CompositeDealer(obj, prop);
}
return null;
}
Obviously (in my mind that is), I'd then have something like this in the CompositeDealer:
public CompositeDealer(Object obj, PropertyInfo propInfo)
{
ComponentDealers = new List<BaseDealer>();
Object compProp = propInfo.GetValue(obj); // The new "origin" object for reflection, this does not work
foreach (var property in compProp.GetType().GetProperties())
{
var dealer = Factory.GetDealer(compProp, property.Name);
if (dealer != null)
{
ComponentDealer.Add(dealer);
}
}
}
As noted in the comment, getting the new "base object" for reflection, that is to start the "second level" of reflection does not work, it returns null.
I really struggle at this stage although I came so far and am pretty close (I think).
Help me StackOverflow,
you're my only hope.
Edit:
So, answering the question what the data would look like:
class A {
int primitiveProp {get;}
}
class B {
A compositeProp {get;}
}
If I were to call the Factory on an instance of A, I'd make a PrimitiveDealer.
If we call it on an instance of B, I'd get a CompositeDealer, which in turn has a primitiveDealer.
Also note that I need the actual property object of the passed instance (since I need to manipulate it) rather than a new object.
Instead of calling different functions to get the properties of your object, dependent on the property type, the function should then call itself with an instance of the object we want to get the properties of.
object o = Activator.CreateInstance(property.PropertyType)
Recursively call the function which gets the properties of this object.
Edit: If you instead need the actual object, ensure to cast it to the correct type.
Type compProp = (Type)propInfo.GetValue(obj);

Using a property of T to create a new object of the property type with the property values?

I need a way to convert the properties of an object of type T to objects of the property type, and values as they are in T. My reason for doing this is so that I can check if the property is or inherits from IEnumerable (Lists, arrays, etc.), and if it does then I need to pass that IEnumerable as an object to be worked on. So far I have
foreach (var propInfo in obj.GetType().GetProperties())
{
var newObject = Activator.CreateInstance(propInfo.PropertyType, propInfo.GetValue(obj));
if (ObjectProcessing.ImplementsIEnumerable(newObject))
{
ObjectProcessing.ObjectQueue.Enqueue(newObject);
}
}
Which unfortunately doesn't work. I cant use CreatInstance<T> because it seems the compiler assumes T is the T in the method signature, which is the source object not the target object.
The question looks like a XY problem. What is the XY Problem?
You do not need to create an instance of the object to see if it implements or is IEnumerable. Let me build upon what you have so far
// This is the example object
public class MyClass {
public IEnumerable A{ get;set;}
public List<int> B{get;set;}
}
var myClass = new MyClass();
foreach (var propInfo in myClass.GetType().GetProperties()) {
var typeOfProperty = propInfo.PropertyType;
var isIEnuerableOrInheritingFromIt = typeof(IEnumerable).IsAssignableFrom(typeOfProperty);
if (isIEnuerableOrInheritingFromIt) {
var objectThatImplementsIEnumerable = propInfo.GetValue(myClass);
// Do stuff with it
}
}

C# Reflection, setting new instance of a null property

I've writing a small method whose sole purpose is to check if a property is null for a given class. If the property is null, then create a new instance of it. I'm getting stuck on part where I'm actually setting a value:
public static void CheckIfPropertyIsNull<TEntity>(SomeBusinessEntity someBusinessEntity) where TEntity : new()
{
var properties = typeof(SomeBusinessEntity).GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
Type currentType = propertyInfo.PropertyType;
if (currentType == typeof(TEntity))
{
var propertyData = propertyInfo.GetValue(someBusinessEntity, null);
if (propertyData == null)
{
object instance = Activator.CreateInstance(typeof(TEntity));
// And then?
//propertyInfo.SetValue(null, instance);
return;
}
}
}
}
I try to use the SetValue() method but with no luck.
In your SetValue you still have to give the instance of the owner of the property: someBusinessEntity.
object instance = new TEntity();
// And then
propertyInfo.SetValue(someBusinessEntity, instance);
Note that your logic seems odd to me. You are using a generic type to set all properties. Why not use the type of the property?

Initialization all properties in a Generic Type?

I want to initialize all public properties of generic type.
I've written the following method :
public static void EmptyModel<T>(ref T model) where T : new()
{
foreach (PropertyInfo property in typeof(T).GetProperties())
{
Type myType = property.GetType().MakeGenericType();
property.SetValue(Activator.CreateInstance(myType));//Compile error
}
}
but it has a compile error
how can I do it?
There are three problems here:
PropertyInfo.SetValue takes two arguments, a reference to an object of to set the property on (or null for static properties)`, and the value to set it too.
property.GetType() will return PropertyInfo. To get the type of the property itself, you want to use property.PropertyType instead.
Your code doesn't handle cases when there is no parameterless constructor on the property type. You can't get too fancy here without radically changing the way you're doing things, so in my code, I'll initialize the property to null if no parameterless constructor is found.
I think what you're looking for is this:
public static T EmptyModel<T>(ref T model) where T : new()
{
foreach (PropertyInfo property in typeof(T).GetProperties())
{
Type myType = property.PropertyType;
var constructor = myType.GetConstructor(Type.EmptyTypes);
if (constructor != null)
{
// will initialize to a new copy of property type
property.SetValue(model, constructor.Invoke(null));
// or property.SetValue(model, Activator.CreateInstance(myType));
}
else
{
// will initialize to the default value of property type
property.SetValue(model, null);
}
}
}

Get Value Of PropertyInfo

I'm creating a small validation framework, I've a custom Validation Attribute which is assignable to methods and a IsValid property in ValidationCore class. When IsValid called inside the method my ValidationCore finds a caller method and get its attribute assigned to method. My custom Validation attribute has a property name named TypeToValidate. So when I find validation attribute I look for any types in class scope of that type. I don't have any problem till now, but the problem is when I want to get the value of property which I've to validate I don't have any instance of that class to get that property value. I don't know how can I handle this situation please help me.
This is my sample :
public class TestClass
{
public static TestModel Model { get; set; }
public static ModelValidator ModelState
{
get { return new ModelValidator(); }
}
[Validate(typeof(TestModel))]
public static void DoSomething()
{
if (ModelState.IsValid)
{
// Do something else....
}
}
}
Edit : This is my IsValid property
public virtual Boolean IsValid
{
get
{
// Get IsValid caller method
var method = GetCallerMethod();
// Get method attribute
var Attrib = GetMethodAttribute(typeof(ValidateAttribute), method);
// Get model to validate inside class scope
var modelProperty = GetModelToValidateInClassScope(Attrib, method);
if (modelProperty != null)
{
ValidateModel(modelProperty);
}
....
}
}
and here is ValidateModel method :
protected virtual void ValidateModel(PropertyInfo modelProperty)
{
// Here I've model property
// But I can't get its value
var model = modelProperty.GetValue(null, null);
var properties = model.GetType().GetProperties(
BindingFlags.FlattenHierarchy |
BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
foreach (var propertyInfo in properties)
{
// Add error to error list
GetPropertyErrors(model, propertyInfo);
}
}
Thanks in advance.
You need an instance for which to get the property value of. It looks like you need to modify the method GetModelToValidateInClassScope so that it returns the instance of the model itself, along with the PropertyInfo.
If this method is changed so it looks something like this (note the new out parameter):
PropertyInfo GetModelToValidateInClassScope(Type attributeType, MethodInfo methodInfo, out object instance)
{
// same implementation as before ...
// assign the model to use,
// which is likely accessible from somewhere in the is method
instance = theModelInstanceFromThisMethod;
// .. or if the property is static, then uncomment the next line:
// instance = null;
// same return value as before ...
}
I'm just guessing here because you didn't provide the implementation of this method. If GetModelToValidateInClassScope doesn't have access to the model instance, then you'll have to get it from somewhere else.
Once you get the model instance, it could be used like the following. Note that ValidateModel has been modified so that it accepts the model instance as the first parameter.
...
// Get model to validate inside class scope
object instance; // <--- will hold the model instance
var modelProperty = GetModelToValidateInClassScope(Attrib, method, out instance);
if (modelProperty != null)
{
ValidateModel(instance, modelProperty); // <--- make sure to pass the instance along!
}
...
protected virtual void ValidateModel(object instance, PropertyInfo modelProperty)
{
// get value of instance property
var model = modelProperty.GetValue(instance, null);
...
}
Answer to the question actually asked
I don't have any problem till now, but the problem is when I want to get the value of property which I've to validate I don't have any instance of that class to get that property value.
If it's a static property, that's fine - just use null as the first argument:
// First argument is the instance: null as it's a static property
// Second argument is indexer arguments: null as we don't have any
var value = property.GetValue(null, null);
From the documentation:
Because static properties belong to the type, not individual objects, get static properties by passing null as the object argument.
Alternative approach
If you're just trying to get the TypeToValidate property from the Validate attribute, then you should have an instance of the attribute, and you can just cast to ValidateAttribute and retrieve the property directly.
Basically, it's not clear where properties really come into what you're trying to do. Your attribute is on a method rather than a property, and your attribute doesn't say which properties to validate...

Categories