我想创建一个通用扩展方法,如果对象或结构的值等于其默认值,该方法将为其设置一个值。
所以我有以下代码:
public static void setIfNull<T>(this T i_ObjectToUpdate, T i_DefaultValue)
{
if (EqualityComparer<T>.Default.Equals(i_ObjectToUpdate, default(T)))
{
i_ObjectToUpdate = i_DefaultValue;
}
}
这是一个调用示例:
public OrganizationalUnit CreateOrganizationalUnit(OrganizationalUnit i_UnitToCreate)
{
i_UnitToCreate.EntityCreationDate.setIfNull(DateTime.Now); //Here is a call
i_UnitToCreate.EntityLastUpdateDate.setIfNull(DateTime.Now); //And another one
m_Context.DomainEntities.Add(i_UnitToCreate);
return i_UnitToCreate;
}
我不知道这是否与此有关,但我使用 Entity Framework 和 MVC。
调试器中实际发生的情况我看到扩展方法中的行 i_ObjectToUpdate = i_DefaultValue;
正在工作并且值发生了变化,但是当调试器退出扩展方法时,我看到i_UnitToCreate.EntityCreationDate
的值保持不变。
知道哪里出了问题吗?
最佳答案
您的代码中有两个引用。其中之一是i_UnitToCreate.EntityCreationDate
,它指向内存中的某个地址。另一个是扩展方法中的 i_ObjectToUpdate
,它最初也指向该地址(您在传递 i_UnitToCreate.EntityCreationDate
引用时创建地址副本按照你的方法)。稍后您将第二个引用更改为指向内存中其他对象,但这不会更改第一个引用,因为它们是独立的。
解决方法
public static void SetIfDefault<T, TProperty>(this T arg,
Expression<Func<T, TProperty>> propertySelector, TProperty value)
{
TProperty currentValue = propertySelector.Compile()(arg);
EqualityComparer<TProperty> comparer = EqualityComparer<TProperty>.Default;
if (!comparer.Equals(currentValue, default(TProperty)))
return;
PropertyInfo property = (PropertyInfo)((MemberExpression)propertySelector.Body).Member;
property.SetValue(arg, value);
}
您可以使用表达式将属性选择器(而不是属性值)传递给扩展方法。从编译表达式中检索值。如果它是默认值,则通过反射(您可以通过转换成员表达式轻松获取PropertyInfo)设置新值。用法:
i_UnitToCreate.SetIfDefault(x => x.EntityCreationDate, DateTime.Now);
i_UnitToCreate.SetIfDefault(x => x.EntityLastUpdateDate, DateTime.Now);
PS 关于我的第一个答案,有一个评论 - 当谈到复制引用值时,我认为通用 T
类型是引用类型。对于值类型(如 DateTime),整个对象都会被复制。它不会改变结果(您不能分配新值),但需要提及。
关于c# - setIfNull 扩展方法不会将值设置给对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13540024/