Skip to content

Commit

Permalink
reference the library LogicExtensions
Browse files Browse the repository at this point in the history
  • Loading branch information
donnytian committed Sep 24, 2023
1 parent 1199c15 commit 7ee9651
Show file tree
Hide file tree
Showing 3 changed files with 5 additions and 119 deletions.
5 changes: 3 additions & 2 deletions Npoi.Mapper/src/Npoi.Mapper/Attributes/ColumnAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using LogicExtensions;

namespace Npoi.Mapper.Attributes;

Expand Down Expand Up @@ -138,7 +139,7 @@ public ColumnAttribute(string name)
return null;
}

Getter ??= MapHelper.CreateConditionalGetter(host, PropertyFullPath);
Getter ??= PropertyFullPath.CreateConditionalGetter<T, object>(host, pathStartsWithHostType: true);
return (Func<T, object>)Getter;
}

Expand All @@ -149,7 +150,7 @@ public ColumnAttribute(string name)
return null;
}

Setter ??= MapHelper.CreateConditionalSetter(host, PropertyFullPath);
Setter ??= PropertyFullPath.CreateConditionalSetter<T, object>(host, pathStartsWithHostType: true);
return (Action<T, object>)Setter;
}

Expand Down
117 changes: 0 additions & 117 deletions Npoi.Mapper/src/Npoi.Mapper/MapHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,123 +485,6 @@ public static (PropertyInfo propertyInfo, string fullPath) GetPropertyInfo<T>(st
return (pi, fullPath);
}

public static Expression<Func<T, object>> CreateSelectorExpression<T>(T host, string propertyFullPath)
{
if (host is null)
{
throw new ArgumentNullException(nameof(host));
}

var parts = propertyFullPath?.Split('.');
if (parts is null || parts.Length == 0)
{
throw new ArgumentException($"Property path is invalid: {propertyFullPath}", nameof(propertyFullPath));
}

if (parts.Length <= 1)
{
throw new ArgumentException($"Property full path should include the host type: {propertyFullPath}", nameof(propertyFullPath));
}

var hostType = host.GetType();
var param = Expression.Parameter(typeof(T), "x"); // T will be 'object' for dynamic
Expression body = Expression.Convert(param, hostType); // force convert to underlying type for dynamic

// Skip the first part, which is the host object type.
for (var i = 1; i < parts.Length; i++)
{
var member = parts[i];
body = Expression.PropertyOrField(body, member);
}

var selector = Expression.Lambda<Func<T, object>>(Expression.Convert(body, ObjectType), param);

return selector;
}

public static Func<T, object> CreateConditionalGetter<T>(T host, string propertyFullPath)
{
var selector = CreateSelectorExpression(host, propertyFullPath);
return CreateConditionalGetter(selector);
}

public static Func<T, object> CreateConditionalGetter<T>(Expression<Func<T, object>> propertySelector)
{
if (propertySelector is not LambdaExpression lambdaExpression)
{
throw new ArgumentException($"Unsupported property selector: {propertySelector}", nameof(propertySelector));
}

var body = lambdaExpression.Body;
var newBody = body;
while (body is MemberExpression or UnaryExpression{ Operand: MemberExpression })
{
var memberAccess = body as MemberExpression ?? (MemberExpression)((UnaryExpression)body).Operand;

if (!memberAccess.Expression.Type.IsValueType)
{
newBody = Expression.Condition(
Expression.Equal(memberAccess.Expression, Expression.Constant(null)),
Expression.Convert(Expression.Constant(null), ObjectType),
newBody);
}

body = memberAccess.Expression;
}

newBody = Expression.Convert(newBody, ObjectType);
return Expression.Lambda<Func<T, object>>(newBody, propertySelector.Parameters.First()).Compile();
}

public static Action<T, object> CreateConditionalSetter<T>(T host, string propertyFullPath)
{
var selector = CreateSelectorExpression(host, propertyFullPath);
return CreateConditionalSetter(selector);
}

public static Action<T, object> CreateConditionalSetter<T>(Expression<Func<T, object>> propertySelector)
{
if (propertySelector is not LambdaExpression lambdaExpression)
{
throw new ArgumentException($"Unsupported property selector: {propertySelector}", nameof(propertySelector));
}

var writeableBody = lambdaExpression.Body is UnaryExpression { Operand: MemberExpression writeableMember }
? writeableMember
: (MemberExpression)lambdaExpression.Body;
var newValueParam = Expression.Parameter(ObjectType, "v");

var rightExpression = Expression.Condition(// Write default value if the new value is null.
Expression.Equal(newValueParam, Expression.Constant(null)),
Expression.Default(writeableBody.Type),
Expression.Convert(newValueParam, writeableBody.Type));
var assignExpression = Expression.Assign(writeableBody, rightExpression);
var statements = new List<Expression> { assignExpression };

var innerBody = writeableBody.Expression;

while (innerBody is MemberExpression or UnaryExpression{ Operand: MemberExpression })
{
var memberAccess = innerBody as MemberExpression ?? (MemberExpression)((UnaryExpression)innerBody).Operand;

if (!memberAccess.Type.IsValueType)
{
var ifNullAssignNew = Expression.IfThen(
Expression.Equal(memberAccess, Expression.Constant(null)),
Expression.Assign(memberAccess, Expression.New(memberAccess.Type)));

statements.Add(ifNullAssignNew);
}

innerBody = memberAccess.Expression;
}

statements.Reverse();
var newBody = Expression.Block(statements);

return Expression.Lambda<Action<T, object>>(newBody, propertySelector.Parameters[0], newValueParam).Compile();
}

/// <summary>
/// Get refined name by removing specified chars and truncating by specified chars.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions Npoi.Mapper/src/Npoi.Mapper/Npoi.Mapper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="LogicExtensions" Version="0.0.3" />
<PackageReference Include="NPOI" Version="2.6.2" />
</ItemGroup>

<ItemGroup Label="SourceLink">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
</ItemGroup>

</Project>

0 comments on commit 7ee9651

Please sign in to comment.