C# 如何使用反射为对象上的所有DateTime属性设置DateTime.Kind

C# 如何使用反射为对象上的所有DateTime属性设置DateTime.Kind,c#,datetime,reflection,C#,Datetime,Reflection,在我的应用程序中,我通过web服务检索域对象。在web服务数据中,我知道所有日期值都是UTC,但web服务没有将其xs:dateTime值格式化为UTC日期。(换句话说,字母Z不会附加到每个日期的末尾以表示UTC。) 此时我无法更改web服务的行为方式,但作为一种解决方法,我创建了一个方法,在web服务中的对象被反序列化后立即调用该方法 private void ExplicitlyMarkDateTimesAsUtc<T>(T obj) where T : class

在我的应用程序中,我通过web服务检索域对象。在web服务数据中,我知道所有日期值都是UTC,但web服务没有将其
xs:dateTime
值格式化为UTC日期。(换句话说,字母
Z
不会附加到每个日期的末尾以表示UTC。)

此时我无法更改web服务的行为方式,但作为一种解决方法,我创建了一个方法,在web服务中的对象被反序列化后立即调用该方法

    private void ExplicitlyMarkDateTimesAsUtc<T>(T obj) where T : class
    {
        Type t = obj.GetType();

        // Loop through the properties.
        PropertyInfo[] props = t.GetProperties();
        for (int i = 0; i < props.Length; i++)
        {
            PropertyInfo p = props[i];
            // If a property is DateTime or DateTime?, set DateTimeKind to DateTimeKind.Utc.
            if (p.PropertyType == typeof(DateTime))
            {
                DateTime date = (DateTime)p.GetValue(obj, null);
                date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
                p.SetValue(obj, date, null);
            }
            // Same check for nullable DateTime.
            else if (p.PropertyType == typeof(Nullable<DateTime>))
            {
                DateTime? date = (DateTime?)p.GetValue(obj, null);
                DateTime? newDate = DateTime.SpecifyKind(date.Value, DateTimeKind.Utc);
                p.SetValue(obj, newDate, null);
            }
        }
    }
private void显式标记日期时间asutc(T obj),其中T:class
{
类型t=obj.GetType();
//循环浏览属性。
PropertyInfo[]props=t.GetProperties();
for(int i=0;i
该方法获取一个对象并循环遍历其属性,查找
DateTime
Nullable
的属性,然后(应该)显式地将每个属性值的
DateTime.Kind
属性设置为
DateTimeKind.Utc

代码不会抛出任何异常,但是
obj
永远不会更改其日期时间属性。在调试器中
p.SetValue(obj,date,null),但从未修改过
obj


为什么没有将更改应用到
obj

在我尝试时效果很好。注意,你只是在改变种类,而不是时间。如果date.HasValue为false,则不能使用date.Value。确保异常不会被静默捕获并绕过其余的属性分配。修正:

            // Same check for nullable DateTime.
            else if (p.PropertyType == typeof(Nullable<DateTime>)) {
                DateTime? date = (DateTime?)p.GetValue(obj, null);
                if (date.HasValue) {
                    DateTime? newDate = DateTime.SpecifyKind(date.Value, DateTimeKind.Utc);
                    p.SetValue(obj, newDate, null);
                }
            }
//对可为空的日期时间进行相同的检查。
else if(p.PropertyType==typeof(可空)){
DateTime?date=(DateTime?)p.GetValue(obj,null);
if(date.HasValue){
DateTime?newDate=DateTime.SpecifyKind(date.Value,DateTimeKind.Utc);
p、 设置值(obj,newDate,null);
}
}
有关博客帖子,请参阅。我使用以下代码将WCF响应对象图转换为所有本地时间:

/// <summary>
/// Since all dates in the DB are stored as UTC, this converts dates to the local time using the Windows time zone settings.
/// </summary>
public static class AllDateTimesAsUTC
{

    /// <summary>
    /// Specifies that an object's dates are coming in as UTC.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static T AllDatesAreUTC<T>(this T obj)
    {
        if (obj == null)
        {
            return default(T);
        }
        IterateDateTimeProperties(obj);
        return obj;
    }

    private static void IterateDateTimeProperties(object obj)
    {
        if (obj == null)
        {
            return;
        }
        var properties = obj.GetType().GetProperties();
        //Set all DaetTimeKinds to Utc
        foreach (var prop in properties)
        {
            var t = prop.PropertyType;
            if (t == typeof(DateTime) || t == typeof(DateTime?))
            {
                SpecifyUtcKind(prop, obj);
            }
            else if (t.IsEnumerable())
            {
                var vals = prop.GetValue(obj, null);
                if (vals != null)
                {
                    foreach (object o in (IEnumerable)vals)
                    {
                        IterateDateTimeProperties(o);
                    }
                }
            }
            else
            {
                var val = prop.GetValue(obj, null);
                if (val != null)
                {
                    IterateDateTimeProperties(val);
                }
            }
        }
        //properties.ForEach(property => SpecifyUtcKind(property, obj));
        return; // obj;
    }

    private static void SpecifyUtcKind(PropertyInfo property, object value)
    {
        //Get the datetime value
        var datetime = property.GetValue(value, null);
        DateTime output;

        //set DateTimeKind to Utc
        if (property.PropertyType == typeof(DateTime))
        {
            output = DateTime.SpecifyKind((DateTime)datetime, DateTimeKind.Utc);
        }

        else if (property.PropertyType == typeof(DateTime?))
        {
            var nullable = (DateTime?)datetime;
            if (!nullable.HasValue) return;
            output = (DateTime)DateTime.SpecifyKind(nullable.Value, DateTimeKind.Utc);
        }
        else
        {
            return;
        }

        Debug.WriteLine("     ***** Converted date from {0} to {1}.", datetime, output);
        datetime = output.ToLocalTime();

        //And set the Utc DateTime value
        property.SetValue(value, datetime, null);
    }
    internal static Type[] ConvertibleTypes = {typeof(bool), typeof(byte), typeof(char),
typeof(DateTime), typeof(decimal), typeof(double), typeof(float), typeof(int), 
typeof(long), typeof(sbyte), typeof(short), typeof(string), typeof(uint), 
typeof(ulong), typeof(ushort)};

    /// <summary>
    /// Returns true if this Type matches any of a set of Types.
    /// </summary>
    /// <param name="types">The Types to compare this Type to.</param>
    public static bool In(this Type type, params Type[] types)
    {
        foreach (Type t in types) if (t.IsAssignableFrom(type)) return true; return false;
    }

    /// <summary>
    /// Returns true if this Type is one of the types accepted by Convert.ToString() 
    /// (other than object).
    /// </summary>
    public static bool IsConvertible(this Type t) { return t.In(ConvertibleTypes); }

    /// <summary>
    /// Gets whether this type is enumerable.
    /// </summary>
    public static bool IsEnumerable(this Type t)
    {
        return typeof(IEnumerable).IsAssignableFrom(t);
    }

    /// <summary>
    /// Returns true if this property's getter is public, has no arguments, and has no 
    /// generic type parameters.
    /// </summary>
    public static bool SimpleGetter(this PropertyInfo info)
    {
        MethodInfo method = info.GetGetMethod(false);
        return method != null && method.GetParameters().Length == 0 &&
             method.GetGenericArguments().Length == 0;
    }

}
//
///由于数据库中的所有日期都存储为UTC,因此会使用Windows时区设置将日期转换为本地时间。
/// 
公共静态类AllDateTimesAsUTC
{
/// 
///指定对象的日期以UTC的形式输入。
/// 
/// 
/// 
/// 
公共静态T AllDatesAreUTC(此T obj)
{
if(obj==null)
{
返回默认值(T);
}
迭代时间属性(obj);
返回obj;
}
私有静态void IterateDateTimeProperties(对象obj)
{
if(obj==null)
{
返回;
}
var properties=obj.GetType().GetProperties();
//将所有DaetTimeKinds设置为Utc
foreach(属性中的var属性)
{
var t=prop.PropertyType;
如果(t==typeof(DateTime)| t==typeof(DateTime?)
{
指定类别(道具、obj);
}
else if(t.IsEnumerable())
{
var VAL=prop.GetValue(对象,空);
如果(VAL!=null)
{
foreach(对象o在(IEnumerable)VAL中)
{
迭代时间属性(o);
}
}
}
其他的
{
var val=prop.GetValue(对象,空);
如果(val!=null)
{
IterateDateTimeProperties(val);
}
}
}
//ForEach(property=>SpecifyUtcKind(property,obj));
return;//obj;
}
私有静态void SpecifyUtcKind(PropertyInfo属性,对象值)
{
//获取日期时间值
var datetime=property.GetValue(值,null);
日期时间输出;
//将DateTimeKind设置为Utc
if(property.PropertyType==typeof(DateTime))
{
输出=DateTime.SpecifyKind((DateTime)DateTime,DateTimeKind.Utc);
}
else if(property.PropertyType==typeof(DateTime?)
{
var nullable=(DateTime?)DateTime;
如果(!nullable.HasValue)返回;
输出=(DateTime)DateTime.SpecifyKind(nullable.Value,DateTimeKind.Utc);
}
其他的
{
返回;
}
WriteLine(“******将日期从{0}转换为{1}.”,datetime,output);
datetime=output.ToLocalTime();
//并设置Utc日期时间值
SetValue(值,日期时间,null);
}
内部静态类型[]可转换类型={typeof(bool)、typeof(byte)、typeof(char),
typeof(日期时间)、typeof(十进制)、typeof(双精度)、typeof(浮点)、typeof(整数),
typeof(长)、typeof(短)、typeof(短)、typeof(字符串)、typeof(uint),
typeof(ulong),typeof(ushort)};
/// 
///如果此类型与一组类型中的任何一个匹配,则返回true。
/// 
///要将此类型与之进行比较的类型。
公共静态布尔输入(此类型,参数
    void svc_ZOut_GetZOutSummaryCompleted(object sender, ZOut_GetZOutSummaryCompletedEventArgs e)
    {
        svc.ZOut_GetZOutSummaryCompleted -= new EventHandler<ZOut_GetZOutSummaryCompletedEventArgs>(svc_ZOut_GetZOutSummaryCompleted);
        svc = null;
        var whenDone = (Action<bool, ZOutResult>)e.UserState;
        if (e.Error != null)
        {
            FireOnExceptionRaised(e.Error);
            whenDone(false, null);
        }
        else
        {
            var res = e.Result.AllDatesAreUTC();
            FireOnSessionReceived(res.IsError, res.Session);
            if (res.IsError == true)
            {
                whenDone(false, null);
            }
            else
            {
                whenDone(true, res.Result);
            }
        }
    }
// Same check for nullable DateTime.
else if (p.PropertyType == typeof(Nullable<DateTime>)) {
    DateTime? date = (DateTime?)p.GetValue(obj, null);
    if (date.HasValue) {
        DateTime? newDate = DateTime.SpecifyKind(date.Value, DateTimeKind.Utc);
        p.SetValue(obj, null, null);
        p.SetValue(obj, newDate, null);
    }
}
public static void ConvertDatesToUtc(this object obj) {
            foreach (var prop in obj.GetType().GetProperties().Where(p => p.CanWrite)) {
                var t = prop.PropertyType;
                if (t == typeof(DateTime)) {
                    //found datetime, specify its kind as utc.
                    var oldValue = (DateTime)prop.GetValue(obj, null);
                    var newValue = DateTime.SpecifyKind(oldValue, DateTimeKind.Utc);
                    prop.SetValue(obj, newValue, null);
                } else if (t == typeof(DateTime?)) {
                    //found nullable datetime, if populated specify its kind as utc.
                    var oldValue = (DateTime?)prop.GetValue(obj, null);
                    if (oldValue.HasValue) {
                        var newValue = (DateTime)DateTime.SpecifyKind(oldValue.Value, DateTimeKind.Utc);
                        prop.SetValue(obj, newValue, null);
                    }
                } else if (typeof(IEnumerable).IsAssignableFrom(t)) {
                    //traverse child lists recursively.
                    var vals = prop.GetValue(obj, null);
                    if (vals != null) {
                        foreach (object o in (IEnumerable)vals) {
                            ConvertDatesToUtc(o);
                        }
                    }
                } else {
                    //traverse child objects recursively.
                    var val = prop.GetValue(obj, null);
                    if (val != null)
                        ConvertDatesToUtc(val);
                }
            }
        }