Well, I always can hardcode checking properties in order to solve my case but I want to do it using reflection.
My generic type:
public class AnalyzedParameter<T>
{
public T Value { get; set; }
public bool Valid { get; set; }
}
My class:
public class Foo
{
public AnalyzedParameter<int> A { get; set; }
public AnalyzedParameter<string> B { get; set; }
}
I need to check each property that has type AnalyzedParameter
by checking Valid
property inside.
So my method has to be like this:
public bool IsValid()
{
var props = GetType().GetProperties().Where(prop => prop.PropertyType == typeof(AnalyzedParameter<>));
var valid = props.All(p => ((AnalyzedParameter<object>) p.GetValue(this)).Valid);
return valid;
}
But it does not work. Any ideas?
CodePudding user response:
The first part answers your question directly - how to make what you're doing work. The second hopefully changes the problem and makes it easier.
I separated out the part that checks all of these Valid
properties into a separate class to make it easier for me to work with. (If this was only for Foo
then you wouldn't need reflection. You already know what properties Foo
has.
public static class Validations
{
// x is a Foo or any other object that
// has properties of type AnalyzedProperty<T>
public static bool IsValid(object x)
{
var analyzedParameterProperties = x.GetType()
.GetProperties().Where(prop =>
prop.PropertyType.GetGenericTypeDefinition() == typeof(AnalyzedParameter<>));
var isValid = analyzedParameterProperties.All(analyzedParameterProperty =>
GetIsValidValue(x, analyzedParameterProperty));
return isValid;
}
private static bool GetIsValidValue(object x, PropertyInfo analyzedParameterProperty)
{
var analyzedParameter = analyzedParameterProperty.GetValue(x);
if (analyzedParameter == null) return false; // or true?
var analyzedParameterIsValidProperty = analyzedParameter.GetType()
.GetProperty("Valid", typeof(bool));
return (bool)analyzedParameterIsValidProperty.GetValue(analyzedParameter);
}
}
The IsValid
method takes an object (like an instance of Foo
) and retrieves all of the properties where the type matches the open generic type AnalyzedParameter<>
.
The messy part is that you can't use that open generic type to read the Valid
property on each AnalyzedParameter
object.
So the second method - GetIsValidValue
- Gets the value of the property - an
AnalyzedParameter
object - Finds a
Valid
property that returnsbool
- Reads that property and returns its value.
This would be much easier if AnalyzedProperty<T>
implemented some interface that had the Valid
property. In that case you could just cast each property value as that interface and read the property that way instead of using reflection to find the Valid
property.
public class AnalyzedParameter<T> : IHasValidation
{
public T Value { get; set; }
public bool Valid { get; set; }
}
public interface IHasValidation
{
public bool Valid { get; set; }
}
Now the rest of the code can be a little simpler:
public static bool IsValid(object x)
{
var analyzedParameterProperties = x.GetType()
.GetProperties().Where(prop =>
typeof(IHasValidation).IsAssignableFrom(prop.PropertyType));
var analyzedParameterValues = analyzedParameterProperties.Select(property =>
property.GetValue(x)).Cast<IHasValidation>();
// This assumes that if the property is null, it's not valid.
// You could instead check for value is null or .Valid == true.
var isValid = analyzedParameterValues.All(value => value?.Valid == true);
return isValid;
}
CodePudding user response:
This doesn't work because the PropertyType
of your instance variables is not AnalyzedParameter<>
but instead AnalyzedParameter<int>
or AnalyzedParameter<string>
.
You will likely need to enumerate the types you wish to check for, and construct concrete types from them. For example, in some test code I put together:
public class AnalyzedParameter<T>
{
public T Value { get; set; }
public bool Valid { get; set; } = false;
}
public class Foo
{
public AnalyzedParameter<int> A { get; set; }
public AnalyzedParameter<string> B { get; set; }
public bool IsValid()
{
var thisType = GetType();
Log.Verbose($"Type: {thisType}");
var thisProperties = thisType.GetProperties();
Log.Verbose($"Properties: {thisProperties}");
foreach (PropertyInfo pi in thisProperties)
{
Log.Verbose($"type:{pi.PropertyType}, name:{pi.Name}");
if (pi.PropertyType == typeof(AnalyzedParameter<>)) Log.Verbose("This property is an AnalyzedParameter<>");
if (pi.PropertyType == typeof(AnalyzedParameter<int>)) Log.Verbose("This property is an AnalyzedParameter<int>");
if (pi.PropertyType == typeof(AnalyzedParameter<string>)) Log.Verbose("This property is an AnalyzedParameter<string>");
}
}
}
[10:25:50 VRB] Type: FooTest.Foo
[10:25:50 VRB] Properties: System.Reflection.PropertyInfo[]
[10:25:50 VRB] type:FooTest.AnalyzedParameter`1[System.Int32], name:A
[10:25:50 VRB] This property is an AnalyzedParameter<int>
[10:25:50 VRB] type:FooTest.AnalyzedParameter`1[System.String], name:B
[10:25:50 VRB] This property is an AnalyzedParameter<string>