C# 在方法中单独传递对象及其子列表属性时,如何对其进行更改?

C# 在方法中单独传递对象及其子列表属性时,如何对其进行更改?,c#,pass-by-reference,variable-assignment,C#,Pass By Reference,Variable Assignment,我有一个通用方法,它接受对象和列表,列表是对象的属性: 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.TbH

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

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);
  }
}
问题是日志对象已设置,但列表未设置。它返回为空,即使它在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);
}
任何要使用方法检索的类都必须实现它:

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

在哪里初始化oLog.LstDetails?在JCLSTBINventoryar的构造函数中是注入它还是直接在构造函数中初始化?您可以在代码中添加初始化部分吗?您正在重置日志引用,因此lst引用不再是intance的属性。您显然是在将对象添加到oLog.ListDetails。然后在方法中覆盖oLog。我不明白你想要实现什么。只从方法中返回一个TJCls对象,并从TJCls日志和列表lst中删除这两个无用的对象,这将更加清晰和简单。这里的SelectMany是否与我使用的foreach循环等效?是的。它将从每个列表中选择每个项,这样您就有了一个IEnumerable项
var oLog = oHistory.GetSingleLog<JClsTbInventory, MyClass>(logId);