上周我安装了Visual Studio 2015 Enterprise
版本(进一步命名为:VS2015
)。我想在切换到新版本之前执行一些测试。例如,项目文件的向后兼容性。我忽略了目前的所有C# 6.0
功能,因为并非所有团队成员都安装了更新以支持C# 6.0
。
我的问题是,使用VS2015
构建的解决方案/项目在异常抛出到使用VS2013 (Premium)
构建的同一解决方案/项目时具有不同的行为。
下面我将使用代码片段来描述使用VS2015
构建时失败的方案。
使用VS2015
构建的项目的行为更改如下:
以下代码会抛出System.ArgumentException
,其中包含以下消息:Static method requires null instance, non-static method requires non-null instance. Parameter name: method
代码内容
//A delegate to convert string values from an array (e3k.Values) to the property type of the desired object.
Func<TE3K, int, Type, object> stringFromDictionary = (e3k, index, type) =>
{
//handle enums
if (type.IsEnum)
{
if (typeof (TE3K) == typeof (VoucherHeader)) //maybe not so good
return VoucherEnumConverter.ToWebEnum(e3k.Values[index], type, e3k.Values);
return DefaultEnumConverter.ToWebEnum(e3k.Values[index], type);
}
//set default value, false if api sends null
if (type == typeof(Boolean) && e3k.Values[index] == null)
return false;
//fix exception when a value like "0" or "1" is converted to boolean.
if (type == typeof(Boolean) && (e3k.Values[index] == "0" || e3k.Values[index] == "1"))
return Convert.ChangeType(Int32.Parse(e3k.Values[index]), type, CultureInfo.InvariantCulture);
//handle nullables
if (Nullable.GetUnderlyingType(type) != null)
return Convert.ChangeType(e3k.Values[index], Nullable.GetUnderlyingType(type), CultureInfo.InvariantCulture);
return Convert.ChangeType(e3k.Values[index], type, CultureInfo.InvariantCulture);
};
MethodInfo getStrValueFromDict = stringFromDictionary.Method;
描述:对象TE3K
是来自外部.dll的对象,我必须将其转换为可以使用的对象。类型为TE3K
的此对象具有一个数组,其值显然都是Strings
。参数int
提供数组的索引(e3k.Values[i]
)参数Type
是必须转换为字符串值的PropertyType
。
//get mapper, sets the index needed in `e3k.Values[index]` for each property of `TWeb`
Dictionary<PropertyInfo, int> mapper = Converter.GetMapper<TE3K, TWeb>();
foreach (var property in mapper)
{
Expression propertyValue = default(Expression);
if (property.Key.PropertyType == typeof(DateTime)) //not relevant for this case
{
propertyValue = Expression.Call(getDateValueFromDict, r, Expression.Constant(property.Value));
}
else if (property.Key.PropertyType == typeof(DateTime?)) //not relevant in this case
{
propertyValue = Expression.Call(getDateValueFromDictSave, r, Expression.Constant(property.Value));
}
else
{
//exception is thrown on this line but only when project is compiled in VS2015
propertyValue = Expression.Call(getStrValueFromDict, r, Expression.Constant(property.Value), Expression.Constant(property.Key.PropertyType));
}
UnaryExpression boxedValue = Expression.Convert(propertyValue, property.Key.PropertyType);
bindings.Add(Expression.Bind(property.Key, boxedValue));
FieldList.Add(property.Value);
}
我现在是在正常情况下导致此异常的原因。当您调用委托中的non static
方法时,它会被抛出,该方法被传递到Expression.Call(_delegate, args, ...)
的第一个参数,或者其中一个参数是非常量值。 (如果我在这里错了,请纠正我,这就是我对此的理解。)
摘要
显然我对这种行为感到很困惑。前面提到的例外仅在使用VS2015
构建项目时发生。使用VS2013
构建时,代码按预期运行。 Visual Studio如何在这两个版本之间构建和优化代码有什么不同?
我尝试了什么
如果您知道原因,请随意解释。如果您需要信息,请询问,如果可以,我会提供。
答案 0 :(得分:1)
如果getStrValueFromDict
是非静态的,则抛出错误,而不是像你已经写过的那样在其中有非静态调用。您需要处理将getStrValueFromDict
编译为实例方法的情况。根据使用的编译器,这肯定会有所不同。
Expression instance = getStrValueFromDict.IsStatic ? null : Expression.Constant(stringFromDictionary.Target);
propertyValue = Expression.Call(instance, getStrValueFromDict, r, Expression.Constant(property.Value), Expression.Constant(property.Key.PropertyType));
以下是一些背景信息,说明为什么现在将某些代理编译为实例方法:https://stackoverflow.com/a/30897727/631802