如何使用非泛型类型获取枚举的默认值?

时间:2019-07-12 13:22:22

标签: c# generics reflection

我有一个方法可以迭代对象的属性,并将值设置为其类型的默认值。一些属性是枚举。我有另一个函数,它获取枚举的默认值(不是0),但是它需要传递当前方法未知的枚举类型。

    [DefaultValue(Red)]
    public enum Colors
    {
        Red = 1,
        green = 2
    }

    // In another class
    public static TEnum GetDefaultValue<TEnum>() where TEnum : struct
    {
        Type t = typeof(TEnum);
        DefaultValueAttribute[] attributes = (DefaultValueAttribute[])t.GetCustomAttributes(typeof(DefaultValueAttribute), false);
        if (attributes != null && attributes.Length > 0)
        {
        return (TEnum)attributes[0].Value;
        }
        else
        {
        return default(TEnum);
        }
    }


    public static void ClearObject<T>(object obj)
    {
        obj = (T)obj;

        PropertyInfo[] props = obj.GetType().GetProperties();

        string propName = "";

        try
        {
        foreach (PropertyInfo pi in props)
        {
            propName = pi.Name;

            Type t = Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType;
            if (t.IsEnum)
            {
            //  This works
            //  var val = EnumFunctions.GetDefaultValue<Colors>();

            // The error is here
            var val = EnumFunctions.GetDefaultValue<t>();
            //                                     ^^^

            pi.SetValue(obj, val);
            }
            // In case of nullable value types int,datetime, etc - set null  
            else if (Nullable.GetUnderlyingType(pi.PropertyType) != null)
            pi.SetValue(obj, null);
            else
            pi.SetValue(obj, null, null);
        }
        }
        catch (Exception e)
        {
        string msg = $"Error for {propName}: {e.Message}";
        throw new Exception(msg);
        }
    }

我尝试过typeof(t)t.GetType()

我希望Colors枚举属性的默认值为Red。导致错误的行是

var val = EnumFunctions.GetDefaultValue<t>();
Error   CS0118  't' is a variable but is used like a type

3 个答案:

答案 0 :(得分:2)

这里不需要泛型

public static object GetDefaultValue(Type type)
{
    DefaultValueAttribute[] attributes = (DefaultValueAttribute[])type.GetCustomAttributes(typeof(DefaultValueAttribute), false);
    if (attributes != null && attributes.Length > 0)
    {
        return attributes[0].Value;
    }
    else
    {
        return null;
    }
}

然后像这样使用它

 var val = EnumFunctions.GetDefaultValue(t);
 if(val != null)
     pi.SetValue(obj, val);

您的困惑之源:

一般而言,泛型不是运行时构造,它们是编译时构造,因此您不能在反射中使用它们,因为反射在运行时起作用。

答案 1 :(得分:0)

您还可以像这样通过反射调用该方法:

typeof(EnumFunctions).GetMethod("GetDefaultValue").MakeGenericMethod(t).Invoke(null, null);

答案 2 :(得分:0)

根据我上面的评论(我想可以发布代码)。我还想确保将枚举实例化为有效值。一些枚举没有0,因此默认的数字类型不起作用。

public MyClass() 
{
    // Sets default property values for all but dates
    Basefunctions.Clear<InternalExaminer>(this);

    // Sets default values by [DefalutValue()] tag.
    foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(this))
    {
        pd.ResetValue(this);
    }

    // Sets date properties to current date.
    Basefunctions.SetDates<MyClass>(this);
}

public static class Basefunctions
{
    public static void SetDates<T>(object obj)
    {
        string propName = "";

        try
        {
            obj = (T)obj;

            PropertyInfo[] props = obj.GetType().GetProperties()
                           .Where(p => p.PropertyType == typeof(DateTime)).ToArray();
            if (props != null)
            {
                DateTime date = DateTime.Now;
                foreach (PropertyInfo pi in props)
                {
                    propName = pi.Name;
                    if (Nullable.GetUnderlyingType(pi.PropertyType) == null)
                        pi.SetValue(obj, date);
                }
            }
        }
        catch (Exception e)
        {
            throw new Exception($"Could not set date for {propName}.\n{e.Message}");
        }
    }

    public static void Clear<T>(object obj)
    {
        obj = (T)obj;

        PropertyInfo[] props = obj.GetType().GetProperties();

        string propName = "";

        try
        {
            foreach (PropertyInfo pi in props)
            {
                propName = pi.Name;

                Type t = Nullable.GetUnderlyingType(pi.PropertyType) ?? pi.PropertyType;

                if (Nullable.GetUnderlyingType(pi.PropertyType) != null)
                    pi.SetValue(obj, null);
                else
                {
                    var val = GetDefaultVal(t);
                    if (t.IsEnum)
                    {
                        // In case enum does not have a 0
                        if (!Enum.IsDefined(t, val))
                            val = EnumMin(pi.PropertyType);
                    }
                    pi.SetValue(obj, val);
                }
            }
        }
        catch (Exception e)
        {
            string msg = $"Error for {propName}: {e.Message}";
            throw new Exception(msg);
        }
    }

    private static object GetDefaultVal(Type type)
    {
        DefaultValueAttribute att = (DefaultValueAttribute)type.GetCustomAttribute(typeof(DefaultValueAttribute));

        if (att != null)
            return att.Value;
        else
            return type.IsValueType ? Activator.CreateInstance(type) : null;
    }

    private static object EnumMin(Type t)
    {
        Array x = Enum.GetValues(t);
        var ret = x.GetValue(0);
        return ret;
    }

    private static object EnumMax(Type t)
    {
        Array x = Enum.GetValues(t);
        var ret = x.GetValue(x.Length - 1);
        return ret;
    }
}