using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace StandardLibrary
{
public static class PropertyPathExtractor
{
///
/// 获得类型下的所有基本类型的访问路径
///
///
///
public static List GetLeafPropertyPaths(Type type)
{
if (type == null) return new List();
var visited = new HashSet();
var paths = new List();
Traverse(type, "", paths, visited);
return paths;
}
private static void Traverse(Type type, string prefix, List paths, HashSet visited)
{
if (type == null || IsSimpleType(type)) return;
if (!visited.Add(type)) // 防止循环引用
return;
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in properties)
{
if (prop.GetIndexParameters().Length > 0) continue; // 跳过索引器
string currentPath = string.IsNullOrEmpty(prefix)
? prop.Name
: $"{prefix}.{prop.Name}";
if (IsSimpleType(prop.PropertyType))
{
// 只有叶子节点(基本类型)才加入路径
paths.Add(currentPath);
}
else
{
// 非简单类型:继续递归,但不记录 currentPath 本身
Traverse(prop.PropertyType, currentPath, paths, visited);
}
}
visited.Remove(type); // 回溯(可选)
}
private static bool IsSimpleType(Type type)
{
if (type == null) return true;
if (type.IsPrimitive || type == typeof(string) || type == typeof(decimal))
return true;
if (type.IsEnum)
return true;
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
return IsSimpleType(type.GetGenericArguments()[0]);
return false;
}
}
public static class PropertyPathHelper
{
//PropertyPathHelper.GetPath(()=>a.b.c),输出a.b.c
public static string GetPath(Expression> expression)
{
return GetMemberPath(expression.Body);
}
private static string GetMemberPath(Expression expression)
{
switch (expression)
{
case MemberExpression memberExpr:
if (memberExpr.Expression is ParameterExpression)
return memberExpr.Member.Name; // 顶层变量(实际不会出现,因为是 Func)
string parentPath = GetMemberPath(memberExpr.Expression);
return parentPath + "." + memberExpr.Member.Name;
case ConstantExpression constExpr:
// 静态成员或 null 常量,无法构成路径
//throw new ArgumentException("表达式不能包含常量或静态成员");
return constExpr.Value.ToString();
default:
throw new ArgumentException($"不支持的表达式类型: {expression.GetType().Name}");
}
}
}
public static class PropertyFinder
{
///
/// 查找指定对象的(非静态)属性中,值为 T 类型(或其派生类)的所有实例。
/// 不递归,仅检查当前对象的属性。
///
public static List FindPropertiesOfType(object obj) where T : class
{
if (obj == null)
return new List();
var result = new List();
var type = obj.GetType();
// 获取所有实例属性(包括私有属性,如不需要可调整 BindingFlags)
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var prop in properties)
{
if (!prop.CanRead)
continue;
// 跳过索引器(如 this[int i])
if (prop.GetIndexParameters().Length > 0)
continue;
try
{
var value = prop.GetValue(obj) as T;
if (value != null)
{
result.Add(value);
}
}
catch (Exception)
{
// 忽略无法读取的属性(如抛异常的 lazy 属性等)
}
}
return result;
}
}
public static class ObjectPropertySetter
{
///
/// Sets the value of a nested property on the specified target object, navigating through the property path.
///
/// This method supports setting values on nested properties by navigating through the
/// specified property path. If any intermediate property in the path is , an instance of
/// the corresponding type will be created, provided the type has a parameterless constructor. The final
/// property in the path will be assigned the specified value, which will be converted to the property's type if
/// necessary.
/// The object on which the property value will be set. Cannot be .
/// The dot-separated path of the property to set. Each segment represents a property name in the hierarchy.
/// The value to assign to the specified property. The value will be converted to the property's type if
/// necessary.
/// Thrown if a property in the path does not exist on the corresponding object type.
/// Thrown if an intermediate property in the path is and cannot be instantiated due to
/// the absence of a parameterless constructor.
public static void SetPropertyValue(object target, string propertyPath, object value)
{
var parts = propertyPath.Split('.');
object current = target;
for (int i = 0; i < parts.Length; i++)
{
var propName = parts[i];
var prop = current.GetType().GetProperty(propName,
BindingFlags.Public | BindingFlags.Instance);
if (prop == null)
throw new ArgumentException($"Property '{propName}' not found on type {current.GetType()}.");
if (i == parts.Length - 1)
{
// 最后一级:赋值
var convertedValue = ConvertValue(value, prop.PropertyType);
prop.SetValue(current, convertedValue);
}
else
{
// 中间级:获取子对象,若为 null 则创建(仅支持无参构造)
var subObject = prop.GetValue(current);
if (subObject == null)
{
var subType = prop.PropertyType;
if (subType.GetConstructor(Type.EmptyTypes) == null)
throw new InvalidOperationException($"Cannot create instance of {subType} (no parameterless constructor).");
subObject = Activator.CreateInstance(subType);
prop.SetValue(current, subObject);
}
current = subObject;
}
}
}
///
/// Converts the specified value to the specified target type.
///
/// This method supports conversion between compatible types, including basic types and
/// enums. If the target type is an enumeration, the method attempts to convert the value to the corresponding
/// enum value.
/// The value to convert. Can be null.
/// The type to which the value should be converted. Must not be null.
/// The converted value as an object of the specified target type, or null if is null.
/// Thrown if the conversion cannot be performed, such as when the value is incompatible with the target type.
private static object ConvertValue(object value, Type targetType)
{
if (value == null)
{
// 返回 targetType 的 default 值,而不是简单返回 null
return GetDefaultValue(targetType);
}
var sourceType = value.GetType();
if (targetType.IsAssignableFrom(sourceType))
return value;
// 尝试类型转换(支持基本类型)
try
{
if (targetType.IsEnum)
return Enum.ToObject(targetType, value);
return Convert.ChangeType(value, targetType);
}
catch (Exception ex)
{
throw new InvalidOperationException($"Cannot convert {value} ({sourceType}) to {targetType}", ex);
}
}
public static object GetDefaultValue(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
// 引用类型(包括 string)或可空值类型(如 int?)的 default 是 null
if (!type.IsValueType)
return null;
// 值类型:使用 Activator.CreateInstance 返回其零初始化值
return Activator.CreateInstance(type);
}
}
}