Skip to content

Commit

Permalink
Add DynamicExpression.RegisterConverter
Browse files Browse the repository at this point in the history
  • Loading branch information
axelheer committed May 22, 2024
1 parent 673bcfa commit 811c9d9
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 0 deletions.
15 changes: 15 additions & 0 deletions src/NeinLinq/DynamicExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,21 @@ public static Expression CreateMemberAccess(Expression target,
return selector.Split('.').Aggregate(target, Expression.PropertyOrField);
}

/// <summary>
/// Registers a custom converter for any type.
/// </summary>
/// <param name="type">Tye type to convert.</param>
/// <param name="converter">The culture-specific converter.</param>
public static void RegisterConverter(Type type, Func<string, IFormatProvider?, object> converter)
{
if (type is null)
throw new ArgumentNullException(nameof(type));
if (converter is null)
throw new ArgumentNullException(nameof(converter));

Cache.Add(type, converter);
}

private static Expression CreateConstant(ParameterExpression target,
Expression selector,
string? value,
Expand Down
14 changes: 14 additions & 0 deletions src/NeinLinq/ObjectCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ private readonly Dictionary<TKey, TValue> cache
private readonly ReaderWriterLockSlim cacheLock
= new();

public void Add(TKey key, TValue value)
{
cacheLock.EnterWriteLock();

try
{
cache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
}

public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
{
cacheLock.EnterReadLock();
Expand Down
43 changes: 43 additions & 0 deletions test/NeinLinq.Tests/DynamicExpressionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,50 @@ public void CreateMemberAccess_NullArgument_Throws()
Assert.Equal("selector", selectorError.ParamName);
}

[Fact]
public void RegisterConverter_NullArgument_Throws()
{
var type = typeof(CustomType);

Func<string, IFormatProvider?, object> converter = (value, _) => CustomType.Create(value);

var typeError = Assert.Throws<ArgumentNullException>(()
=> DynamicExpression.RegisterConverter(null!, converter));
var converterError = Assert.Throws<ArgumentNullException>(()
=> DynamicExpression.RegisterConverter(type, null!));

Assert.Equal("type", typeError.ParamName);
Assert.Equal("converter", converterError.ParamName);
}

[Fact]
public void RegisterConverter_ValidArguments_Works()
{
DynamicExpression.RegisterConverter(typeof(CustomType), (value, _) => CustomType.Create(value));

var predicate = DynamicQuery.CreatePredicate<Model>("Value", DynamicCompare.Equal, "narf");

var actual = Assert.IsType<CustomType>(
Assert.IsAssignableFrom<ConstantExpression>(
Assert.IsAssignableFrom<BinaryExpression>(
predicate.Body)
.Right)
.Value)
.Value;

Assert.Equal("narf", actual);
}

private class CustomType
{
public string Value { get; private set; } = "";

public static CustomType Create(string value)
=> new() { Value = value };
}

private class Model
{
public CustomType? Value { get; set; }
}
}

0 comments on commit 811c9d9

Please sign in to comment.