如何在方法中分别传递对象及其子列表 属性 时对其进行更改?

how to make changes on an object and its child list property when passing them separately in method?

我有一个通用方法,它接受对象和一个列表,列表是对象的 属性:

public void GetSingleLog<TJCls, TListObj>(int logId, out TJCls log, List<TListObj> lst)
{
  var json = (from j in context.TbHistoryLog where j.Id == logId select j.ObjectJson).First();
  var lists = context.TbHistoryLog_Lists.Where(x => x.LogId == logId).Select(x => x.ListJson);
  log = AuditHelper.DeserializeObject<TJCls>(json);
  foreach (var item in lists)
  {
    var listJson = AuditHelper.DeserializeObject<List<TListObj>>(item);
    lst.AddRange(listJson);
  }
}

我这样称呼它:

JClsTbInventory oLog = new JClsTbInventory();
oHistory.GetSingleLog(logId, out oLog, oLog.LstDetails);

问题是设置了日志对象,但没有设置列表。它返回为空,即使它在 GetSingleLog.

中有数据

肮脏的解决方法

这是肮脏且低效的(因为它会使用表达式和反射,它们很慢),但它允许您在不更改的情况下使用您的(坏的)模型:

public void GetSingleLog<TJCls, TListObj>(int logId, out TJCls log, Expression<Func<TJCls, List<TListObj>>> listSetter)
{
    var json = (from j in context.TbHistoryLog where j.Id == logId select j.ObjectJson).First();
    var lists = context.TbHistoryLog_Lists.Where(x => x.LogId == logId).Select(x => x.ListJson);

    log = AuditHelper.DeserializeObject<TListContainer>(json);

    var list = lists.SelectMany(j => AuditHelper.DeserializeObject<List<TListObj>>(j)).ToList();

    var property = (listSetter.Body as MemberExpression)?.Member as PropertyInfo;
    if (property == null) throw new Exception("Expression is not a reference to a property");
    property.SetValue(log, list, null);
}

可以这样使用:

JClsTbInventory oLog;
oHistory.GetSingleLog(logId, out oLog, o => o.LstDetails);

基于继承的方法

这种方法更合理,将使用继承来实现相同的结果,同时保持模型的一致性。

您需要这样的界面:

public interface IListContainer<TItem>
{
    void SetList(List<TItem> list);
}

您想要使用您的方法检索的任何 class 都必须实现它:

public class JClsTbInventory : IListContainer<MyClass>
{
    // ... other properties

    public List<MyClass> LstDetails { get; set; }

    public void SetList(List<MyClass> list)
    { 
        LstDetails = list;
    }

所以您可以使用更简单的方法来检索您的列表:

public TListContainer GetSingleLog<TListContainer, TItem>(int id)
    where TListContainer : IListContainer<TItem>
{
    var json = (from j in context.TbHistoryLog where j.Id == logId select j.ObjectJson).First();
    var lists = context.TbHistoryLog_Lists.Where(x => x.LogId == logId).Select(x => x.ListJson);

    var log = AuditHelper.DeserializeObject<TListContainer>(json);

    var list = lists.SelectMany(j => AuditHelper.DeserializeObject<List<TItem>>(j)).ToList();

    log.SetList(list);

    return log;
}

这样使用:

var oLog = oHistory.GetSingleLog<JClsTbInventory, MyClass>(logId);