如何在使用接口列表的同时在c#中深度克隆列表
本文关键字:列表 深度 接口 | 更新日期: 2023-09-27 17:57:26
我有以下接口
public interface IReportFilter
{
IReportColumn ReportColumn { get; set; }
FilterType Type { get; set; }
string Value { get; set; }
string FormattedValue { get; }
string BuildSqlFilter(string parameterName);
List<IReportFilter> SubFilters { get; set; }
FilterOperator SqlOperator { get; set; }
FilterOperator SubFiltersOperator { get; set; }
}
我有一个类实现它,就像这个
public class ReportFilter : IReportFilter
{
...
...
}
在我的项目中的另一个类中,我有以下代码
List<IReportFilter> filters = new List<IReportFilter>
{
new ReportFilter
{
ReportColumn = new ReportColumn{ ColumnKey = "Result.IsCompleted"},
Value = "1",
SubFilters = new List<IReportFilter>
{
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Jones"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Smith"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ AggregateFunction = SqlAggregateFunctions.Count}, Type = FilterType.GreaterThenOrEqualTo ,Value = "0" },
}
},
};
我希望能够将我的filters
对象传递给一个方法,该方法将根据条件分离我的过滤器。
下面是我写的一个方法,递归地分离我的过滤器
private List<IReportFilter> ExtractFiltersByAType(List<IReportFilter> filters, bool IsStandard = true)
{
List<IReportFilter> validFilters = new List<IReportFilter>();
foreach(var filter in filters)
{
if (filter.SubFilters != null && filter.SubFilters.Any())
{
//At this point we know there are some sub filters
filter.SubFilters = ExtractFiltersByAType(filter.SubFilters, IsStandard);
}
if( (IsStandard && !IsAggregate(filter.ReportColumn.AggregateFunction) ) || (!IsStandard && IsAggregate(filter.ReportColumn.AggregateFunction) ) )
{
validFilters.Add(filter);
}
}
return validFilters;
}
此方法的问题是通过引用传递变量filters
,而不是创建对象的副本。这意味着我所做的任何更改都将更改原始filters
对象!我真的不理解C#中的这种行为,这让我的生活变得悲惨!
无论如何,我做了一些研究,发现在将filters
对象传递给我的方法之前,我需要对其进行深度克隆。
我尝试使用以下方法来深度克隆我的对象
public static T Clone<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
然后我就这么用
var copyOfFilters = Clone(filters);
但这给了我一个错误,因为我的SubFilters
对象是用接口构造的!
无法创建类型为的实例报表引擎。支持ReportsGenerator。汇报合同。IReportFilter。类型是接口或抽象类,不能实例化。路径"[0]"。ReportColumn’,第1行,位置17。
如何正确克隆对象?
我也很好奇为什么c中会有这样的行为?
我也很好奇为什么c中会有这样的行为?
不能实例化接口。接口只提供类型需要遵守的约定。但它没有提供该约定的实现。
因此,当您试图将某些JSON反序列化为接口类型时,这是不起作用的,因为反序列化程序无法实例化该(接口)类型。它需要一个具体的类型,例如ReportFilter
。因此,可以调用JsonConvert.DeserializeObject<ReportFilter>(serialized)
,它就会工作。
但是,由于您在泛型方法中执行此操作,因此尝试将其反序列化为类型T
。该类型T
来自该方法的泛型类型参数,该参数是从对该方法的调用中推断出来的。在这种情况下,您可能会传递一个IReportFilter
对象,因此在编译时这是用于T
的类型(无论该对象是否为实际的ReportFilter
)。
为了改变这一点,您必须将其明确地称为ReportFilter
:
var copyOfFilter = Clone((ReportFilter)filter);