如何在方法中分别传递对象及其子列表 属性 时对其进行更改?
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);
我有一个通用方法,它接受对象和一个列表,列表是对象的 属性:
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);