在AssignmentExpression中使用的MethodCallExpression返回默认值
本文关键字:MethodCallExpression 返回 默认值 AssignmentExpression | 更新日期: 2023-09-27 18:06:56
我正在为我的公司开发一个简单的ORM,并使用反射从查询到目前为止自动填充属性。这显然是相当慢的,我想用表达式树来提高性能。我花了大量的时间跟随示例并阅读适当的调用,现在我的代码编译并执行了!然而,我有一个MethodCallExpression执行基本的DBNull检查和类似的似乎工作正常,但是当值被分配给属性时,它发送类型的默认值。
首先是实际代码:
public static void PopulateFromReaderUsingExpression(Descriptor descriptor, IDataRecord reader)
{
if (descriptor == null)
throw new ArgumentNullException("descriptor");
if (reader == null)
throw new ArgumentNullException("reader");
string[] AvailableColumnsInReader = new string[reader.FieldCount];
for (int i = 0; i <= reader.FieldCount - 1; i++)
{
AvailableColumnsInReader[i] = reader.GetName(i).ToUpper(CultureInfo.InvariantCulture);
}
var statements = new List<Expression>();
ParameterExpression readerExp = Expression.Parameter(typeof(IDataRecord));
ParameterExpression descriptorExp = Expression.Variable(descriptor.GetDescriptorType(), "descriptor");
BinaryExpression createInstanceExp = Expression.Assign(
descriptorExp, Expression.New(descriptor.GetDescriptorType()));
statements.Add(createInstanceExp);
foreach (KeyValuePair<PropertyInfo, PropertyMapping> pair in descriptor.ReadablePropertiesAndDataNames
.Where(property => AvailableColumnsInReader.Contains(property.Value.ReturnName.ToUpper(CultureInfo.InvariantCulture))))
{
MemberExpression propertyExp = Expression.Property(descriptorExp, pair.Key);
IndexExpression readValue =
Expression.MakeIndex(readerExp, typeof(IDataRecord).GetProperty("Item", new[] { typeof(string) }),
new[] { Expression.Constant(pair.Value.ReturnName) });
MethodCallExpression castValueExp =
Expression.Call(typeof(Descriptor)
.GetMethod("CastValue",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[]
{
typeof(Type), typeof(object), typeof(object)
},
null), Expression.Constant(pair.Key.PropertyType, typeof(Type)), readValue, Expression.Constant(null));
BinaryExpression assignmentExp = Expression.Assign(propertyExp, Expression.Convert(castValueExp, pair.Key.PropertyType));
statements.Add(assignmentExp);
}
var body = Expression.Block(new ParameterExpression[] { descriptorExp }, statements);
Expression.Lambda<Action<IDataRecord>>(body, readerExp).Compile()(reader);
}
正在被MethodCallExpression及其重载调用的方法:
/// <summary>
/// Detects if a value is DBNull, null, or has value.
/// </summary>
/// <param name="newType">The new type.</param>
/// <param name="value">The value.</param>
/// <param name="defaultValue">The default value.</param>
/// <param name="typeName">Name of the type from the database (used for date/time to string conversion).</param>
/// <returns>Value as type T if value is not DBNull, null, or invalid cast; otherwise defaultValue.</returns>
public static object CastValue(Type newType, object value, object defaultValue, string typeName)
{
object returnValue;
if (value is DBNull || value == null)
returnValue = defaultValue;
else if (newType == typeof(bool) && (value.GetType() == typeof(Int16) || value.GetType() == typeof(Int32)))
returnValue = ((object)(int.Parse(value.ToString(), CultureInfo.InvariantCulture) > 0 ? true : false));
else if (newType == typeof(int) && value.GetType() == typeof(long))
returnValue = ((object)((int)((long)value)));
else if (newType == typeof(int) && value.GetType() == typeof(decimal))
returnValue = ((object)((int)((decimal)value)));
else if (newType == typeof(string))
{
returnValue = value.ToString();
if (!string.IsNullOrEmpty(typeName))
if (typeName == "date")
returnValue = ((DateTime)value).ToString("MM/dd/yyyy", CultureInfo.CurrentCulture);
}
else
returnValue = value;
return returnValue;
}
/// <summary>
/// Casts the value.
/// </summary>
/// <param name="newType">The new type.</param>
/// <param name="value">The value.</param>
/// <param name="defaultValue">The default value.</param>
/// <returns>System.Object.</returns>
public static object CastValue(Type newType, object value, object defaultValue)
{
return CastValue(newType, value, defaultValue, null);
}
我已经确认值正在进入方法并返回,但是在此过程中丢失了,我的猜测是在赋值操作中。
这里我将包括代码示例中使用的相关方法签名:
public virtual Dictionary<PropertyInfo, PropertyMapping> ReadablePropertiesAndDataNames
/// <summary>
/// THe object Orochi CRUDE uses to map properties to database actions.
/// </summary>
public class PropertyMapping
{
/// <summary>
/// Initializes a new instance of the <see cref="PropertyMapping" /> class.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="parameterName">Name of the parameter.</param>
/// <param name="returnName">Name of the return.</param>
/// <exception cref="System.ArgumentNullException">property</exception>
public PropertyMapping(PropertyInfo property, string returnName)
{
if (property == null)
throw new ArgumentNullException("property");
Contract.EndContractBlock();
this.ReturnName = !string.IsNullOrWhiteSpace(returnName) ? returnName : property.Name;
}
/// <summary>
/// Gets the name of the return.
/// </summary>
/// <value>
/// The name of the return.
/// </value>
public string ReturnName { get; private set; }
}
这是我的语句块中的DebugInfo:
.Block(Models.Billing.Claims.BillingQueue $descriptor) {
$descriptor = .New Models.Billing.Claims.BillingQueue();
$descriptor.ClaimWorkQueueId = (System.Int32).Call Orochi.CrudeData.Descriptor.CastValue(
.Constant<System.Type>(System.Int32),
$var1.Item["ClaimWorkQueueId"],
null);
$descriptor.WorkQueueName = (System.String).Call Orochi.CrudeData.Descriptor.CastValue(
.Constant<System.Type>(System.String),
$var1.Item["WorkQueueName"],
null);
$descriptor.Count = (System.Int32).Call Orochi.CrudeData.Descriptor.CastValue(
.Constant<System.Type>(System.Int32),
$var1.Item["ClaimCount"],
null)
}
我错过了我正在创建一个对象的新实例并为它设置值而不是通过引用。我添加了返回语句并修改了代码以使用返回值。
/// <summary>
/// Builds the mapping expression.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <param name="reader">The reader.</param>
/// <returns>LambdaExpression.</returns>
public static Expression<Func<IDataRecord, object>> BuildMappingExpression(IDescriptor descriptor, IDataRecord reader, string[] availableColumns)
{
var statements = new List<Expression>();
ParameterExpression readerExp = Expression.Parameter(typeof(IDataRecord));
ParameterExpression descriptorExp = Expression.Variable(descriptor.GetDescriptorType(), "descriptor");
BinaryExpression createInstanceExp = Expression.Assign(
descriptorExp, Expression.New(descriptor.GetDescriptorType()));
statements.Add(createInstanceExp);
foreach (KeyValuePair<PropertyInfo, PropertyMapping> pair in descriptor.ReadablePropertiesAndDataNames
.Where(property => availableColumns.Contains(property.Value.ReturnName.ToUpper(CultureInfo.InvariantCulture))))
{
MemberExpression propertyExp = Expression.Property(descriptorExp, pair.Key);
IndexExpression readValue =
Expression.MakeIndex(readerExp, typeof(IDataRecord).GetProperty("Item", new[] { typeof(string) }),
new[] { Expression.Constant(pair.Value.ReturnName) });
MethodCallExpression castValueExp =
Expression.Call(typeof(Descriptor)
.GetMethod("CastValue",
BindingFlags.Static | BindingFlags.Public,
null,
new Type[]
{
typeof(Type), typeof(object), typeof(object)
},
null), Expression.Constant(pair.Key.PropertyType, typeof(Type)), readValue, Expression.Constant(null));
BinaryExpression assignmentExp = Expression.Assign(propertyExp, Expression.Convert(castValueExp, pair.Key.PropertyType));
statements.Add(assignmentExp);
}
statements.Add(descriptorExp);
var body = Expression.Block(new ParameterExpression[] { descriptorExp }, statements);
return Expression.Lambda<Func<IDataRecord, object>>(body, readerExp);
}