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...
Related
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);
I have a generic class with a generic method:
public class GenericClass<T> where T : class
{
public void GenericMethod<T>(T item)
{
// do work here
}
}
I also have an object with multiple properties, some of which can be other objects:
public class TestObject
{
public ChildObject ChildObject { get; set; }
}
I am then attempting to use a generic method which will reflect through TestObject and call GenericMethod for all properties that are in and of themselves custom classes such as ChildObject (I do have a way of determining this based on inheritance, however for the sake of keeping it simple did not include that code for this example):
public void ReflectingMethod<T>(T item)
{
var properties = item.GetType().GetProperties();
foreach (var property in properties)
{
var type = property.PropertyType;
dynamic propertyModel = property.GetValue(model, null);
var castedObject = Convert.ChangeType(propertyModel, type);
var genericClass = Activator.CreateInstance(typeof(GenericClass<>).MakeGenericType(type));
var method = genericClass.GetType().GetMethod("GenericMethod", new [] { type });
method.Invoke(castedObject, null);
}
}
The problem is that whether I attempt to change property's type (as shown in the above example) or I pass property directly to method.Invoke, such as:
method.Invoke(propertyModel, null);
I still receive the same error:
Object does not match target type.
At RunTime method is:
GenericMethod(TestProject.ChildObject)
And castedObject is:
TestProject.ChildObject
I am confused as to why I am getting the error I am, when it would appear that the casted object is exactly of the type that the method is looking for.
EDIT 1
Included the call to GetValue that I had originally left out when posting the question.
The call
method.Invoke(castedObject, null);
is incorrect. It should be
method.Invoke(genericClass, new object[] { castedObject });
Since you are trying to call an instance method, the first argument to Invoke(object, object[]) must be the this instance. For static method, pass null as first argument. Method arguments are always passed via the second object[] argument of the Invoke method.
Assuming you have a class, say, MainClass. Assuming this class has a property, MainProperty, whose type is also another custom class, AlternateClass. Given as...
public class MainClass
{
...
public AlternateClass MainProperty { get; set; }
...
}
public class AlternateClass
{
...
public int someAction()
{
...
}
...
}
I'd like to know how to invoke the someAction() method for MainProperty using reflection, the alternative of which is:
MainClass instanceOfMainClass = new MainClass();
instanceOfMainClass.MainProperty.someAction();
You need to get the type and an instance of each layer. Reflection gets properties and methods from the type system but performs work on instances.
Not Test, probably has a few errors in it.
//First Get the type of the main class.
Type typeOfMainClass = instanceOfMainClass.GetType();
//Get the property information from the type using reflection.
PropertyInfo propertyOfMainClass = typeOfMainClass.GetProperty("MainProperty");
//Get the value of the property by combining the property info with the main instance.
object instanceOfProperty = propertyOfMainClass.GetValue(instanceOfMainClass);
//Rinse and repeat.
Type typeofMainProperty = intanceOfProperty.GetType();
MethodInfo methodOfMainProperty = typeofMainProperty.GetMethod("someAction");
methodOfMainProperty.Invoke(instanceOfMainProperty);
You'll need to make use of the GetMethod() and GetProperty() Reflection methods. You will call the respective method on the type, and then use the returned MethodInfo or PropertyInfo object against the original object.
For example:
MainClass theMain = new MainClass();
PropertyInfo mainProp = typeof(MainClass).GetProperty("MainProperty");
AlternateClass yourAlternate = mainProp.GetValue(mainClass);
MethodInfo someActionMethod = typeof(AlternateClass).GetMethod("someAction");
someActionMethod.Invoke(yourAlternate);
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);
}
}
}
Basically, some internal check that happens in the static System.Linq.Expressions.Expression.Bind() method says "Method is not a property accessor" on my property that is clearly a property. Using Reflector, I've minimized the amount of code causing the problem, and I can't for the life of me figure out why this would happen. My only guess is that it has something to do with the fact that the property isn't on the class itself, but I would think this should still work:
I've tried to make a small example with the least amount of code possible. The code below should run in its entirety.
using System;
using System.Reflection;
public class Base
{
public virtual int Id { get; set; }
}
// As you can see, SubClass does not override the Id property of Base.
public class SubClass : Base { }
class Program
{
static void Main(string[] args)
{
// Getting the property directly from the type.
PropertyInfo propertyInfo = typeof(SubClass).GetProperty("Id");
MethodInfo setMethod = propertyInfo.GetSetMethod();
/* Code from here on out is from the System.Linq.Expressions.Bind() method (the one
that accepts a MethodInfo argument). This method causes GetProperty to be called
and retrieve what should be the same PropertyInfo. It fails here, saying something
along the lines of "Method is not a property accessor." which doesn't make sense. */
PropertyInfo propertyInfo2 = GetProperty(setMethod);
}
private static PropertyInfo GetProperty(MethodInfo mi)
{
// Not sure if it matters, but declaringType here is "Base".
Type declaringType = mi.DeclaringType;
BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public;
bindingAttr |= mi.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
foreach (PropertyInfo info in declaringType.GetProperties(bindingAttr))
{
// For the "Id" property, info.CanRead is true, but CheckMethod is false.
if (info.CanRead && CheckMethod(mi, info.GetGetMethod(true)))
return info;
// For the "Id" property, info.CanWrite is true, but CheckMethod is false.
if (info.CanWrite && CheckMethod(mi, info.GetSetMethod(true)))
return info;
}
// This gets thrown after passing by the "Id" property that is the one I'm looking for.
throw new Exception("Method is not a property accessor");
}
private static bool CheckMethod(MethodInfo method, MethodInfo propertyMethod)
{
// These are not equal, so it goes to the next check. In the debugger, they appear identical when I look through the object tree.
if (method == propertyMethod)
return true;
Type declaringType = method.DeclaringType;
return ((declaringType.IsInterface && (method.Name == propertyMethod.Name)) && (declaringType.GetMethod(method.Name) == propertyMethod));
}
}
If anyone could help I would greatly appreciate it! I'm very much lost at this point.
Edit - If you substitute typeof(SubClass) with typeof(Base), it works, so it's something related to that relationship. I guess I could cut the issue off at the root by making an extension method like typeof(SubClass).GetPropertyFromActualClass("Id") but I'm not sure how to perform that check.
The property and method infos of Base and SubClass are indeed not equal, even if SubClass has no own implementation, as can be seen here:
var subPropertyInfo = typeof(SubClass).GetProperty("Id");
var subPropertyInfoSetter = subPropertyInfo.GetSetMethod();
var basePropertyInfo = typeof(Base).GetProperty("Id");
var basePropertyInfoSetter = basePropertyInfo.GetSetMethod();
Console.WriteLine(subPropertyInfo == basePropertyInfo); // false
Console.WriteLine(subPropertyInfoSetter == basePropertyInfoSetter); // false
If you use mi.ReflectedType instead of mi.DeclaringType, the check succeeds:
var type = subPropertyInfoSetter.ReflectedType;
Console.WriteLine(type.GetProperty("Id").GetSetMethod()
== subPropertyInfoSetter); // true