using Microsoft.Extensions.Localization; using Microsoft.Extensions.Primitives; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text.RegularExpressions; using WalkingTec.Mvvm.Core.Extensions; namespace WalkingTec.Mvvm.Core { /// /// 属性辅助类 /// public static class PropertyHelper { public static object GetExpressionRootObj(Expression expression) { if (expression == null) { return ""; } Expression me = null; LambdaExpression le = null; if (expression is MemberExpression) { me = expression as MemberExpression; } if (expression is LambdaExpression) { le = expression as LambdaExpression; if (le.Body is MemberExpression) { me = le.Body as MemberExpression; } if (le.Body is UnaryExpression) { me = (le.Body as UnaryExpression).Operand as MemberExpression; } } while (me != null && me.NodeType == ExpressionType.MemberAccess) { Expression exp = (me as MemberExpression).Expression; if (exp is MemberExpression) { me = exp as MemberExpression; } else if (exp is MethodCallExpression) { var mexp = exp as MethodCallExpression; if (mexp.Method.Name == "get_Item") { object index = 0; if (mexp.Arguments[0] is MemberExpression) { var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value; index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj); } else { index = (mexp.Arguments[0] as ConstantExpression).Value; } me = mexp.Object as MemberExpression; } } else { me = exp; break; } } if(me.NodeType == ExpressionType.Constant) { return (me as ConstantExpression)?.Value; } return null; } public static Func GetPropertyExpression(Type objtype, string property) { property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); List level = new List(); if (property.Contains('.')) { level.AddRange(property.Split('.')); } else { level.Add(property); } var pe = Expression.Parameter(objtype); var member = Expression.Property(pe, objtype.GetSingleProperty(level[0])); for (int i = 1; i < level.Count; i++) { member = Expression.Property(member, member.Type.GetSingleProperty(level[i])); } return Expression.Lambda>(member, pe).Compile(); } /// /// 获取属性名 /// /// 属性表达式 /// 是否获取全部级别名称,比如a.b.c /// 属性名 public static string GetPropertyName(this Expression expression, bool getAll = true) { if (expression == null) { return ""; } MemberExpression me = null; LambdaExpression le = null; if (expression is MemberExpression) { me = expression as MemberExpression; } if (expression is LambdaExpression) { le = expression as LambdaExpression; if (le.Body is MemberExpression) { me = le.Body as MemberExpression; } else if (le.Body is UnaryExpression) { me = (le.Body as UnaryExpression).Operand as MemberExpression; } else if(le.Body is MethodCallExpression mexp && mexp.Method.Name == "get_Item") { object index = 0; me = mexp.Object as MemberExpression; } } string rv = ""; if (me != null) { rv = me.Member.Name; } while (me != null && getAll && me.NodeType == ExpressionType.MemberAccess) { Expression exp = me.Expression; if (exp is MemberExpression) { rv = (exp as MemberExpression).Member.Name + "." + rv; me = exp as MemberExpression; } else if (exp is MethodCallExpression) { var mexp = exp as MethodCallExpression; if (mexp.Method.Name == "get_Item") { object index = 0; if (mexp.Arguments[0] is MemberExpression) { var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value; index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj); } else { index = (mexp.Arguments[0] as ConstantExpression).Value; } rv = (mexp.Object as MemberExpression).Member.Name + "[" + index + "]." + rv; me = mexp.Object as MemberExpression; } } else { break; } } return rv; } public static Expression GetMemberExp(this ParameterExpression self, Expression member) { return self.GetMemberExp(member.GetPropertyName()); } public static Expression GetMemberExp(this ParameterExpression self, string memberName) { var names = memberName.Split(','); Expression rv = Expression.PropertyOrField(self, names[0]); ; for (int i = 1; i < names.Length; i++) { rv = Expression.PropertyOrField(rv, names[i]); } return rv; } /// /// 获取属性名的Id形式,将属性名中的.转换为_,适合作为HTML中的Id使用 /// /// 属性表达式 /// 是否获取全部级别名称,比如a.b.c /// 属性Id public static string GetPropertyId(this Expression expression, bool getAll = true) { return GetPropertyName(expression, getAll).GetIdByName(); } /// /// 获取正则表达式错误 /// /// 属性信息 /// 错误文本 public static string GetRegexErrorMessage(this MemberInfo pi) { string rv = ""; if (pi.GetCustomAttributes(typeof(RegularExpressionAttribute), false).FirstOrDefault() is RegularExpressionAttribute dis && !string.IsNullOrEmpty(dis.ErrorMessage)) { rv = dis.ErrorMessage; if (CoreProgram._localizer != null) { rv = CoreProgram._localizer[rv]; } } else { rv = ""; } return rv; } /// /// 获取属性显示名称 /// /// 属性信息 /// /// 属性名称 public static string GetPropertyDisplayName(this MemberInfo pi, IStringLocalizer local = null) { string rv = ""; if (pi.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() is DisplayAttribute dis && !string.IsNullOrEmpty(dis.Name)) { rv = dis.Name; if (local == null) { if (CoreProgram._localizer != null) { rv = CoreProgram._localizer[rv]; } } else { rv = local[rv]; } } else { rv = pi.Name; } return rv; } /// /// 获取属性显示名称 /// /// 属性表达式 /// /// 属性显示名称 public static string GetPropertyDisplayName(this Expression expression, IStringLocalizer local = null) { return GetPropertyDisplayName(expression.GetPropertyInfo(), local); } /// /// 获取枚举显示名称 /// /// 枚举值 /// 枚举显示名称 public static string GetEnumDisplayName(this Enum value) { return GetEnumDisplayName(value.GetType(), value.ToString()); } /// /// 获取属性信息 /// /// 属性表达式 /// 属性信息 public static PropertyInfo GetPropertyInfo(this Expression expression) { MemberExpression me = null; LambdaExpression le = null; if (expression is MemberExpression) { me = expression as MemberExpression; } if (expression is LambdaExpression) { le = expression as LambdaExpression; if (le.Body is MemberExpression) { me = le.Body as MemberExpression; } if (le.Body is UnaryExpression) { me = (le.Body as UnaryExpression).Operand as MemberExpression; } } PropertyInfo rv = null; if (me != null) { rv = me.Member.DeclaringType.GetSingleProperty(me.Member.Name); } return rv; } /// /// 获取属性值 /// /// 属性表达式 /// 属性所在实例 /// 属性值 public static object GetPropertyValue(this object obj, LambdaExpression exp) { //获取表达式的值,并过滤单引号 try { var expValue = exp.Compile().DynamicInvoke(obj); object val = expValue; return val; } catch { return ""; } } public static object GetPropertyValue(this object obj, string property) { //获取表达式的值,并过滤单引号 try { return obj.GetType().GetSingleProperty(property).GetValue(obj); ; } catch { return ""; } } public static List GetPropertySiblingValues(this object obj, string propertyName) { if(obj == null) { return new List(); } Regex reg = new Regex("(.*?)\\[\\-?\\d?\\]\\.(.*?)$"); var match = reg.Match(propertyName); if (match.Success) { var name1 = match.Groups[1].Value; var name2 = match.Groups[2].Value; var levels = name1.Split('.'); var objtype = obj.GetType(); var pe = Expression.Parameter(objtype); var member = Expression.Property(pe, objtype.GetSingleProperty(levels[0])); for (int i = 1; i < levels.Length; i++) { member = Expression.Property(member, member.Type.GetSingleProperty(levels[i])); } var pe2 = Expression.Parameter(member.Type.GetGenericArguments()[0]); var cast = Expression.Call(typeof(Enumerable), "Cast", new Type[] { pe2.Type }, member); var name2exp = Expression.Property(pe2, pe2.Type.GetSingleProperty(name2)); var selectexp = Expression.Call(name2exp, "ToString", Type.EmptyTypes); Expression select = Expression.Call( typeof(Enumerable), "Select", new Type[] { pe2.Type, typeof(string) }, cast, Expression.Lambda(selectexp, pe2)); var lambda = Expression.Lambda(select, pe); var rv = new List(); try { rv = (lambda.Compile().DynamicInvoke(obj) as IEnumerable)?.ToList(); } catch { } return rv; } else { return new List(); } } /// /// 判断属性是否必填 /// /// 属性信息 /// 是否必填 public static bool IsPropertyRequired(this MemberInfo pi) { bool isRequired = false; if (pi != null) { //如果需要显示星号,则判断是否是必填项,如果是必填则在内容后面加上星号 //所有int,float。。。这种Primitive类型的,肯定都是必填 Type t = pi.GetMemberType(); if (t != null && (t.IsPrimitive() || t.IsEnum() || t == typeof(decimal) || t == typeof(Guid))) { isRequired = true; } else { //对于其他类,检查是否有RequiredAttribute,如果有就是必填 if (pi.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() is RequiredAttribute required && required.AllowEmptyStrings == false) { isRequired = true; } else if (pi.GetCustomAttributes(typeof(KeyAttribute), false).FirstOrDefault() != null) { isRequired = true; } } } return isRequired; } /// /// 设置属性值 /// /// 属性所在实例 /// 属性名 /// 要赋的值 /// 属性前缀 /// 是否为字符串格式的值 public static void SetPropertyValue(this object source, string property, object value, string prefix = null, bool stringBasedValue = false) { try { property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); List level = new List(); if (property.Contains('.')) { level.AddRange(property.Split('.')); } else { level.Add(property); } if (!string.IsNullOrWhiteSpace(prefix)) { level.Insert(0, prefix); } object temp = source; Type tempType = source.GetType(); for (int i = 0; i < level.Count - 1; i++) { var member = tempType.GetMember(level[i])[0]; if (member != null) { var va = member.GetMemberValue(temp); if (va != null) { temp = va; } else { var newInstance = member.GetMemberType().GetConstructor(Type.EmptyTypes).Invoke(null); member.SetMemberValue(temp, newInstance, null); temp = newInstance; } tempType = member.GetMemberType(); } } var memberInfos = tempType.GetMember(level.Last()); if (!memberInfos.Any()) { return; } var fproperty = memberInfos[0]; if (value == null || ((value is StringValues s) && StringValues.IsNullOrEmpty(s))) { fproperty.SetMemberValue(temp, null, null); return; } bool isArray = false; if (value != null && value.GetType().IsArray == true) { isArray = true; } if (stringBasedValue == true) { Type propertyType = fproperty.GetMemberType(); if (propertyType.IsGeneric(typeof(List<>)) == true) { var list = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null) as IList; var gs = propertyType.GenericTypeArguments; try { if (value.GetType() == typeof(StringValues)) { var strVals = (StringValues)value; var a = strVals.ToArray(); for (int i = 0; i < a.Length; i++) { list.Add(a[i].ConvertValue(gs[0])); } } else if (isArray) { var a = (value as object[]); for (int i = 0; i < a.Length; i++) { list.Add(a[i].ConvertValue(gs[0])); } } else { list = value.ConvertValue(propertyType) as IList; } } catch { } fproperty.SetMemberValue(temp, list, null); } else if (propertyType.IsArray) { try { var strVals = (StringValues)value; var eletype = propertyType.GetElementType(); var arr = Array.CreateInstance(eletype, strVals.Count); for (int i = 0; i < arr.Length; i++) { arr.SetValue(strVals[i].ConvertValue(eletype), i); } fproperty.SetMemberValue(temp, arr, null); } catch { } } else { if (isArray) { var a = (value as object[]); if (a.Length == 1) { value = a[0]; } } if (value is string) { value = value.ToString().Replace("\\", "/"); } fproperty.SetMemberValue(temp, value, null); } } else { if (value is string) { value = value.ToString().Replace("\\", "/"); } fproperty.SetMemberValue(temp, value, null); } } catch { } } /// /// 根据MemberInfo获取值 /// /// MemberInfo /// 所在实例 /// 如果是数组,指定数组下标。默认为null /// MemberInfo的值 public static object GetMemberValue(this MemberInfo mi, object obj, object[] index = null) { object rv = null; if (mi.MemberType == MemberTypes.Property) { rv = ((PropertyInfo)mi).GetValue(obj, index); } else if (mi.MemberType == MemberTypes.Field) { rv = ((FieldInfo)mi).GetValue(obj); } return rv; } /// /// 设定MemberInfo的值 /// /// MemberInfo /// 所在实例 /// 要赋的值 /// 如果是数组,指定数组下标。默认为null public static void SetMemberValue(this MemberInfo mi, object obj, object val, object[] index = null) { object newval = val; if (val is string s) { if (string.IsNullOrEmpty(s)) { val = null; } } if (val != null && val.GetType() != mi.GetMemberType()) { newval = val.ConvertValue(mi.GetMemberType()); } if (mi.MemberType == MemberTypes.Property) { ((PropertyInfo)mi).SetValue(obj, newval, index); } else if (mi.MemberType == MemberTypes.Field) { ((FieldInfo)mi).SetValue(obj, newval); } } /// /// 获取某个MemberInfo的类型 /// /// MemberInfo /// 类型 public static Type GetMemberType(this MemberInfo mi) { Type rv = null; if (mi != null) { if (mi.MemberType == MemberTypes.Property) { rv = ((PropertyInfo)mi).PropertyType; } else if (mi.MemberType == MemberTypes.Field) { rv = ((FieldInfo)mi).FieldType; } } return rv; } /// /// 获取枚举显示名称 /// /// 枚举类型 /// 枚举值 /// 枚举显示名称 public static string GetEnumDisplayName(Type enumType, string value) { string rv = ""; FieldInfo field = null; if (enumType.IsEnum()) { field = enumType.GetField(value); } //如果是nullable的枚举 if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) { field = enumType.GenericTypeArguments[0].GetField(value); } if (field != null) { var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); if (attribs.Count > 0) { rv = ((DisplayAttribute)attribs[0]).GetName(); if (CoreProgram._localizer != null) { rv = CoreProgram._localizer[rv]; } } else { rv = value; } } return rv; } public static string GetEnumDisplayName(Type enumType, int value) { string rv = ""; FieldInfo field = null; string ename = ""; if (enumType.IsEnum()) { ename = enumType.GetEnumName(value); field = enumType.GetField(ename); } //如果是nullable的枚举 if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) { ename = enumType.GenericTypeArguments[0].GetEnumName(value); field = enumType.GenericTypeArguments[0].GetField(ename); } if (field != null) { var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); if (attribs.Count > 0) { rv = ((DisplayAttribute)attribs[0]).GetName(); if (CoreProgram._localizer != null) { rv = CoreProgram._localizer[rv]; } } else { rv = ename; } } return rv; } /// /// 转化值 /// /// 要转换的值 /// 转换后的类型 /// 转换后的值 public static object ConvertValue(this object value, Type propertyType) { object val = null; if (propertyType.IsGeneric(typeof(Nullable<>)) == true) { var gs = propertyType.GenericTypeArguments; try { val = ConvertValue(value, gs[0]); } catch { } } else if (propertyType.IsEnum()) { val = Enum.Parse(propertyType, value.ToString()); } else if (propertyType == typeof(string)) { val = value?.ToString().Trim(); } else if (propertyType == typeof(Guid)) { bool suc = Guid.TryParse(value?.ToString(), out Guid g); if (suc) { val = g; } else { val = Guid.Empty; } } else if (propertyType == typeof(DateRange)) { if (DateRange.TryParse(value.ToString(), out var result)) { val = result; } else { val = DateRange.Default; } } else { try { if (value.ToString().StartsWith("`") && value.ToString().EndsWith("`")) { string inner = value.ToString().Trim('`').TrimEnd(','); if (!string.IsNullOrWhiteSpace(inner)) { val = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null); string[] pair = inner.Split(','); var gs = propertyType.GetGenericArguments(); foreach (var p in pair) { (val as IList).Add(Convert.ChangeType(p, gs[0])); } } } else { val = Convert.ChangeType(value.ToString(), propertyType); } } catch { } } return val; } public static object MakeList(Type innerType, string propertyName, object[] values) { object rv = typeof(List<>).MakeGenericType(innerType).GetConstructor(Type.EmptyTypes).Invoke(null); var mi = rv.GetType().GetMethod("Add"); var con = innerType.GetConstructor(Type.EmptyTypes); foreach (var item in values) { var newobj = con.Invoke(null); newobj.SetPropertyValue(propertyName, item); mi.Invoke(rv, new object[] { newobj }); } return rv; } } }