【问题标题】:C# DateTime returns default value when set up with reflectionC# DateTime 在使用反射设置时返回默认值
【发布时间】:2015-02-19 18:38:37
【问题描述】:

我在一个类中有一个静态方法,它在运行时设置一个对象,如下所述:http://benohead.com/create-anonymous-types-at-runtime-in-c-sharp/

对于新创建的对象,我添加来自不同对象的组合属性,这些对象被发送到我的方法,我在反射中设置值并返回新创建的对象。所有值似乎都有值(到目前为止,我测试了 string 和 int) - 但值在那里。

问题是当我将 DateTime 值设置为 DateTime 属性时 - 返回的值是 01/01/0001 而不是我设置的日期。

这是在反射中设置值的代码:

foreach (string key in values.Keys)
{
    if (sqlParams == null || sqlParams.Contains(key))
    {
        PropertyValue propertyValue = values[key];
        object val = propertyValue.Value;
        if (val == null)
            val = getDefaultValue(propertyValue.PropertyType);
         else if (propertyValue.PropertyType == typeof(DateTime) && (DateTime)propertyValue.Value == DateTime.MinValue)
            val = new DateTime(1982, 5, 6);// (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
         myType.GetProperty(key).SetValue(obj, val);
    }
}

为什么没有正确返回 DateTime 值?

编辑

完整代码:

    private static object createDummyObject(Dictionary<string, PropertyValue> values, List<string> sqlParams)
    {
        // Code for creating .NET objects at runtime thanks to:
        // http://benohead.com/create-anonymous-types-at-runtime-in-c-sharp/

        AssemblyBuilder dynamicAssembly =
            AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Poco.Sql.Assembly"),
            AssemblyBuilderAccess.Run);

        ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("Poco.Sql.Module");
        TypeBuilder dynamicType = dynamicModule.DefineType("Poco.Sql.DynamicType", TypeAttributes.Public);

        foreach(string key in values.Keys)
        {
            if (sqlParams == null || sqlParams.Contains(key))
            {
                PropertyValue propertyValue = values[key];
                addProperty(dynamicType, key, propertyValue.PropertyType);
            }
        }

        Type myType = dynamicType.CreateType();
        object obj = Activator.CreateInstance(myType);

        foreach (string key in values.Keys)
        {
            if (sqlParams == null || sqlParams.Contains(key))
            {
                PropertyValue propertyValue = values[key];
                object val = propertyValue.Value;
                if (val == null)
                    val = getDefaultValue(propertyValue.PropertyType);
                else if (propertyValue.PropertyType == typeof(DateTime) && (DateTime)propertyValue.Value == DateTime.MinValue)
                    val = new DateTime(1982, 5, 6);// (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
                myType.GetProperty(key).SetValue(obj, val);
            }
        }

        return obj;
    }

    private static void addProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType)
    {
        const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;

        FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private);
        PropertyBuilder property = typeBuilder.DefineProperty(propertyName, System.Reflection.PropertyAttributes.None, propertyType, new[] { propertyType });

        MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_value", getSetAttr, propertyType, Type.EmptyTypes);
        ILGenerator getIl = getMethodBuilder.GetILGenerator();
        getIl.Emit(OpCodes.Ldarg_0);
        getIl.Emit(OpCodes.Ldfld, field);
        getIl.Emit(OpCodes.Ret);

        MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_value", getSetAttr, null, new[] { propertyType });
        ILGenerator setIl = setMethodBuilder.GetILGenerator();
        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, field);
        setIl.Emit(OpCodes.Ret);

        property.SetGetMethod(getMethodBuilder);
        property.SetSetMethod(setMethodBuilder);
    }

    private static object getDefaultValue(Type t)
    {
        if (t == typeof(DateTime))
            return DateTime.MinValue;
        else if (t.IsValueType)
            return Activator.CreateInstance(t);

        return null;
    }

以及上面代码中使用的 PropertyValue 类:

class PropertyValue
{
    public object Value { get; set; }
    public Type PropertyType { get; set; }
}

【问题讨论】:

  • 请展示一个简短但完整的程序来说明问题。如果我们能重现问题,帮助您会容易得多。
  • 我的通灵能力告诉我,您生成的代码在struct 类型和装箱方面存在问题,但由于您的问题不包括相关代码,因此他们可以帮助您。
  • 我已经添加了上面的代码
  • 太棒了!您能否缩短代码,以便保留重现问题所需的部分?确保它仍然可以自行编译...
  • 当您使用调试器单步执行此代码时会发生什么? propertyValue.PropertyType 的值是多少? propertyValue.PropertyType == typeof(DateTime)? (DateTime)propertyValue.Value == DateTime.MinValue?

标签: c# .net datetime reflection


【解决方案1】:

也许问题就在这里?

private static object getDefaultValue(Type t)
    {
        if (t == typeof(DateTime))
            return DateTime.MinValue;
        else if (t.IsValueType)
            return Activator.CreateInstance(t);

        return null;
    }

日期存储为 64 位有符号整数,表示自 01/01/0001 上午 12:00 以来的“滴答”数(1 滴答 = 100 纳秒)。当您调用 DateTime.MinValue 时,输出为 01/01/0001。

【讨论】:

    猜你喜欢
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-23
    相关资源
    最近更新 更多