如何在非泛型类型中使用反射

问题描述 投票:1回答:1

我已经在这里花了数小时来寻找问题的答案,所以如果这是重复的查询,我们感到抱歉。如果是这样,请指出正确的方向。如果没有,请参见下文,我的任务如下:

创建一个可以动态检查数据库以查看某个对象是否存在值的函数。

[基本上,用户单击将项目移动到另一个舞台的按钮。下一阶段可能/可能不会在进入该阶段之前有要求。如果存在要求,则有两个数据点发送给我:

  • ReflectionClass(字符串)[我将在这里使用DbSet字符串值或Class字符串值]
  • ReflectionProperty(字符串)

使用这两段数据,我需要检查数据库(最好通过DbSet,使用LINQ或Reflection

ReflectionClass变量可以引用数据库中5个表之一。因此,从本质上讲,我需要一种表达方式:db.[DbSet].Any(w=>w.ID == PipelineID && w.[ReflectionProperty] != null)或类似的内容...

我已经尝试过使用ExpressionTrees,但无法使Func<T,bool>Type变量一起使用。请参阅下面的代码,这将起作用,但是我知道使用反射可以更有效地做到这一点,我只是不知道如何。

public async Task<Feedback> vStageReqFields(Guid NextStageID, Guid PipelineID)
{
  Feedback f = new Feedback();
  bool Valid = true;
  string InvalidList = string.Empty;
  List<Domain.Pipeline.Pipeline> pipelines = new List<Domain.Pipeline.Pipeline>();
  List<Domain.Pipeline.Billing> billings = new List<Domain.Pipeline.Billing>();
  try
  {
    //Get a list of Validations needed before advancing Stage...
    var validations = db.PipelineStageRequiredFields.Any(a=>a.StageID == NextStageID) ? db.PipelineStageRequiredFields.Where(w=>w.StageID == NextStageID).ToList() : null;
    //If Validations exist, start validatiing...
    if(validations != null && validations.Any())
    {
      Type objectType = (from asm in AppDomain.CurrentDomain.GetAssemblies()
                         from type in asm.GetTypes()
                         where type.IsClass && type.FullName == "Domain.Pipeline.Pipeline" // static class to find Assembly info, all v.ReflectionClasses come from the same Assembly...
                         select type).SingleOrDefault();          
      foreach (var v in validations)
      {
        if(Utility.HasProperty(objectType, v.RefelectionProperty))//Check to see if ReflectionsClass has ReflectionProperty
        {
          //Switch Statement for Reflection Class to Check Property Value...
          switch (v.RefelectionClass)
          {
            case "Domain.Pipeline.Pipeline":
            pipelines = GetAllMembers(db, "Pipelines").OfType<Domain.Pipeline.Pipeline>().Where(w => w.ID == PipelineID).ToList(); //Get all Pipeline Objects...
            if (pipelines.Any())
            {
              var model = pipelines.FirstOrDefault();
              var value = model.GetType().GetProperty(v.RefelectionProperty).GetValue(model, null); //Check if Required ReflectionProperty has a value...
              if (value == null)
              {
                Valid = false;
                if (string.IsNullOrEmpty(InvalidList))
                {
                  InvalidList = "The following fields are required: " + v.RefelectionProperty;
                }
                else
                {
                  InvalidList = InvalidList + ", " + v.RefelectionProperty;
                }
              }
            }
            else
            {
              f.Success = false;
              f.Type = FeedbackType.Error;
              f.SuccessMsg = "Error: Could not find a Pipeline with this ID: '" + PipelineID.ToString() + "'";
            }
            break;
          case "Domain.Pipeline.Billing":
            billings = GetAllMembers(db, "Billings").OfType<Domain.Pipeline.Billing>().Where(w => w.PipelineID == PipelineID).OrderByDescending(o => o.EffectiveDate).ToList();
            if (billings.Any())
            {
              var model = billings.FirstOrDefault();
              var value = model.GetType().GetProperty(v.RefelectionProperty).GetValue(model, null);
              if (value == null)
              {
                Valid = false;
                if (string.IsNullOrEmpty(InvalidList))
                {
                  InvalidList = "The following fields are required: " + v.RefelectionProperty;
                }
                else
                {
                  InvalidList = InvalidList + ", " + v.RefelectionProperty;
                }
              }
            }
            else
            {
              f.Success = false;
              f.Type = FeedbackType.Error;
              f.SuccessMsg = "Error: Could not find a Pipeline with this ID: '" + PipelineID.ToString() + "'";
            }
            break;
          default:
            f.Success = false;
            f.Type = FeedbackType.Error;
            f.SuccessMsg = "Error: Could not find any Data in the " + v.RefelectionClass + " table for this Pipeline: '" + PipelineID.ToString() + "'";
            break;
          }
        }
        else
        {
          f.Success = false;
          f.Type = FeedbackType.Error;
          f.SuccessMsg = "The " + v.RefelectionClass + " does not have a Property of " + v.RefelectionProperty;             
        }
      }
    }
    //No Validations Exist, User can proceed...
    else
    {
      f.Success = true;
      f.Type = FeedbackType.Success;
      f.SuccessMsg = "Success! There are no required fields for the next stage.";
    }
  }
  catch(Exception ex)
  {
    f.Success = false;
    f.Type = FeedbackType.Error;
    f.SuccessMsg = ITool.GetExceptionDetails(ex);
  }
  return f;
}

这里是另一个功能:

static IEnumerable GetAllMembers(DbContext DB, string dbSetName)
{
  var model = DB.GetType().GetProperty(dbSetName);
  return (IEnumerable)model.GetValue(DB);
}
c# linq system.reflection
1个回答
0
投票

考虑以下重构,以删除重复的代码并使它更干燥(不要重复自己)。

public Feedback vStageReqFields(Guid NextStageID, Guid PipelineID) {
    Feedback feedback = new Feedback();
    List<string> required = new List<string>();
    List<string> errors = new List<string>();
    StringBuilder msg = new StringBuilder();
    try {
        //Get a list of Validations needed before advancing Stage...
        var validations = db.PipelineStageRequiredFields.Where(w => w.StageID == NextStageID);
        //If Validations exist, start validatiing...
        if (validations.Any()) {
            foreach (var field in validations) {
                var className = field.RefelectionClass;
                object model = null;
                //Switch Statement for Reflection Class to Check Property Value...
                switch (className) {
                    case "Domain.Pipeline.Pipeline":
                        model = db.Pipelines.FirstOrDefault(p => p.ID == PipelineID);
                        break;
                    case "Domain.Pipeline.Billing":
                        model = db.Billings.Where(w => w.PipelineID == PipelineID).OrderByDescending(o => o.EffectiveDate).FirstOrDefault();
                        break;
                    default:
                        errors.Add("Could not find any Data in the " + className + " table for this Pipeline: '" + PipelineID.ToString() + "'");
                        continue;
                }
                validate(field, PipelineID, model, required, errors);
            }

            if (required.Any()) {
                msg.Append("The following fields are required: ")
                    .AppendLine(string.Join(", ", required));
            }
            if (errors.Any()) {
                msg.AppendLine(string.Join(Environment.NewLine, errors));
            }
        }
        if (msg.Length > 0) {
            feedback.Success = false;
            feedback.Type = FeedbackType.Error;
            feedback.SuccessMsg = msg.ToString();
        } else {
            feedback.Success = true;
            feedback.Type = FeedbackType.Success;
            feedback.SuccessMsg = "Success! There are no required fields for the next stage.";
        }
    } catch (Exception ex) {
        feedback.Success = false;
        feedback.Type = FeedbackType.Error;
        feedback.SuccessMsg = ITool.GetExceptionDetails(ex);
    }
    return feedback;
}

使用强类型查找所需的对象模型。

支持的validate方法如下所示>>

private void validate(PipelineStageRequiredField field, Guid PipelineID, object model, List<string> required, List<string> errors) {
    if (model != null) {
        var propertyName = field.RefelectionProperty;
        var objectType = model.GetType();
        var propertyInfo = getProperty(objectType, propertyName);
        if (propertyInfo != null) {
            var isValidModel = buildRequiredFieldCheckDelegate(objectType, propertyInfo);
            if (!(bool)isValidModel.DynamicInvoke(model)) {
                required.Add(propertyInfo.Name);
            }
        } else {
            errors.Add("The " + field.RefelectionClass + " does not have a Property of " + propertyName);
        }
    } else {
        errors.Add("Error: Could not find a " + field.RefelectionClass + " with this Pipeline: '" + PipelineID.ToString() + "'");
    }
}

private static PropertyInfo getProperty(Type type, string propertyName) {
    return type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
}

可以在其中构建表达式以检查必填字段是否具有值的地方

private Delegate buildRequiredFieldCheckDelegate(Type type, PropertyInfo propertyInfo) {
    //Func<T, bool>
    var delegateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
    var prpertyDefaultValue = getDefaultValue(propertyInfo.PropertyType);
    // p => p.Property != default(typeof(TProperty))

    // p =>
    var parameter = Expression.Parameter(type, "p");
    // p => p.Property
    var property = Expression.Property(parameter, propertyInfo);
    // default(TProperty);
    var defaultValue = Expression.Constant(prpertyDefaultValue);
    // p => p.Property != default(TProperty)
    var body = Expression.NotEqual(property, defaultValue);
    // Func<T, bool> = T p => p.Property != default(TProperty)
    var lambda = Expression.Lambda(delegateType, body, parameter);

    return lambda.Compile();
}

private static object getDefaultValue(Type type) {
    return type.IsValueType ? Activator.CreateInstance(type) : null;
}
© www.soinside.com 2019 - 2024. All rights reserved.