【问题标题】:How do I use reflection to read properties with the same generic type but different generic arguments?如何使用反射来读取具有相同泛型类型但不同泛型参数的属性?
【发布时间】:2021-11-24 22:05:37
【问题描述】:

好吧,我总是可以硬编码检查属性以解决我的问题,但我想使用反射来完成。

我的通用类型:

public class AnalyzedParameter<T>
{
    public T Value { get; set; }

    public bool Valid { get; set; }
}

我的班级:

public class Foo
{
    public AnalyzedParameter<int> A { get; set; }

    public AnalyzedParameter<string> B { get; set; }
}

我需要通过检查内部的Valid 属性来检查具有AnalyzedParameter 类型的每个属性。

所以我的方法必须是这样的:

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;
    }

但它不起作用。有什么想法吗?

【问题讨论】:

    标签: c# reflection


    【解决方案1】:

    第一部分直接回答了你的问题——如何让你正在做的事情发挥作用。第二个有望改变问题并使其变得更容易。

    我将检查所有这些Valid 属性的部分分离到一个单独的类中,以便我更容易使用。 (如果这仅适用于Foo,那么您将不需要反射。您已经知道Foo 具有哪些属性。

    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);
        }
    }
    

    IsValid 方法接受一个对象(如Foo 的实例)并检索类型与开放的泛型类型AnalyzedParameter&lt;&gt; 匹配的所有属性。

    混乱的部分是你不能使用开放的泛型类型来读取每个AnalyzedParameter 对象上的Valid 属性。

    所以第二种方法——GetIsValidValue

    • 获取属性的值 - AnalyzedParameter 对象
    • 查找返回boolValid 属性
    • 读取该属性并返回其值。

    如果AnalyzedProperty&lt;T&gt; 实现了一些具有Valid 属性的接口,这会容易得多。在这种情况下,您可以将每个属性值转换为该接口并以这种方式读取属性,而不是使用反射来查找 Valid 属性。

    public class AnalyzedParameter<T> : IHasValidation
    {
        public T Value { get; set; }
    
        public bool Valid { get; set; }
    }
    
    public interface IHasValidation
    {
        public bool Valid { get; set; }
    }
    

    现在剩下的代码可以简单一点:

    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;
    }
    

    【讨论】:

    • 是的!只有当我完成今天的工作并走出家门时,我才想到了关于界面的想法。谢谢!
    【解决方案2】:

    这不起作用,因为您的实例变量的PropertyType 不是AnalyzedParameter&lt;&gt;,而是AnalyzedParameter&lt;int&gt;AnalyzedParameter&lt;string&gt;

    您可能需要枚举您希望检查的类型,并从中构造具体类型。例如,在我整理的一些测试代码中:

    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>
    

    【讨论】:

      猜你喜欢
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-10
      • 1970-01-01
      • 1970-01-01
      • 2023-02-14
      相关资源
      最近更新 更多