使用VS 2015

时间:2015-08-21 06:54:52

标签: c# visual-studio-2013 visual-studio-2015

上周我安装了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如何在这两个版本之间构建和优化代码有什么不同?

我尝试了什么

  • 在发布/调试上进行编译都不会改变行为。
  • 更改C#版本也不会改变任何内容。

如果您知道原因,请随意解释。如果您需要信息,请询问,如果可以,我会提供。

1 个答案:

答案 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