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