I have a interesting case here . I have a method call as
bool pass= Check.CheckNotNull<RemoveRoleFromUserCommand>(x => x.RoleName, x => x.UserId);
Now I want to Make this method definition as something like this ..
public static void CheckNotNull<T>(params Expression<Func<T, object>>[] #params)
{
return #params.All(x=> ..... );
}
How to check for all of the values in #params delegate for all values that I have passed.
Well, if you want to invoke the delegates, you need an instance of T. So add that as an argument.
public static bool CheckNotNull<T>(T item, params Func<T, object>[] #params)
{
return #params.All(selector => selector(item) != null );
}
In response to the comment:
public static bool CheckNotNull<T>(T item, params Func<T, object>[] #params)
{
return #params.All(selector =>
{
var selected = selector(item);
return selected is string? string.IsNullOrEmpty(selected as string) : selected != null;
} );
}
Related
I have a class RemoteData like below,
public class RemoteData
{
public RemoteData(string Message, string IP)
{
this.IP = IP;
this.Message = Message;
}
public string IP;
public string Message;
}
Now I have a IObservable<T> method UdpStream like below,
public static IObservable<RemoteData> UdpStream(IPEndPoint endpoint, Func<string, RemoteData> processor)
{
return Observable.Using(() => new UdpClient(endpoint),
udpClient => Observable.Defer(() =>
udpClient.ReceiveAsync().ToObservable()).Repeat().Select(result => processor(Encoding.UTF8.GetString(result.Buffer))));
}
Now how to call UdpStream, how to pass Func parameter?
var stream = UdpStream(new IPEndPoint(IPAddress.Any, 514), 2nd Param);
Func<T, U> represents a delegate that takes a T parameter and returns U. You can initialize a Func<T, U> using a method reference that matches that signature, or using a lambda expression.
Using a Func<,> as parameter is a common idiom for a callback. For example, if you have a method similar to this:
public static void Method(Func<T, U> func)
{
// ...
}
We can expect that Method will call whaterver you pass in the func parameter. In fact, this happens in the code your present (the parameter Func<string, RemoteData> processor is called where it says processor(Encoding.UTF8.GetString(result.Buffer))).
Now, you have Func<string, RemoteData>, thus you need a method that takes string and returns RemoteData. For example:
public static RemoteData Example(string input)
{
// ...
}
// ...
var observable = UdpStream(endpoint, Example);
I want to create a Linq-Extension to distinct and filter my User objects within one method:
public static List<User> FilterDistinct<TKey>(this IEnumerable<User> source, Func<User, TKey> key)
{
return source.Where(x => key(x) != null && key(x).ToString() != string.Empty).Select(x => key(x)).Distinct().ToList();
}
The call should look like userList.FilterDistinct(x => x.LastName)
But there is still a Syntax error within my code I can't figure out.
Error:
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
What is returned from your LINQ query will be of type List<TKey> - ie, you're using a Func<User,TKey> to Select from your original list.
However, on the body of the extension method you've said it will return a List<User>.
So, then the function you pass in is pulling just the LastName from your users and returning a distinct list of them. Your return is List<string> not List<User> as you probably expect.
IMO, #tym32167's answer breaks desired behavior, since you need List<User> as output.
You need to build up custom EqualityComparer<User> to call Distinct on User objects. Something like this:
static class MyExtensions
{
private class UserByKeyComparer<TKey> : EqualityComparer<User>
{
private readonly Func<User, TKey> keySelector;
private readonly EqualityComparer<TKey> keyComparer;
public UserByKeyComparer(Func<User, TKey> keyFunc)
{
this.keySelector = keyFunc;
this.keyComparer = EqualityComparer<TKey>.Default;
}
public override bool Equals(User x, User y)
{
return keyComparer.Equals(keySelector(x), keySelector(y));
}
public override int GetHashCode(User obj)
{
return keyComparer.GetHashCode(keySelector(obj));
}
}
public static List<User> FilterDistinct<TKey>(this IEnumerable<User> source, Func<User, TKey> keySelector)
{
return source
.Where(x => keySelector(x) != null && keySelector(x).ToString() != string.Empty)
.Distinct(new UserByKeyComparer<TKey>(keySelector))
.ToList();
}
}
Another option is to use GroupBy (but I think, that it will be slower):
public static List<User> FilterDistinct<TKey>(this IEnumerable<User> source, Func<User, TKey> keySelector)
{
return source
.Where(x => keySelector(x) != null && keySelector(x).ToString() != string.Empty)
.GroupBy(keySelector)
.Select(g => g.First())
.ToList();
}
Try to edit return value of your method.
public static List<TKey> FilterDistinct<TKey>(this IEnumerable<User> source, Func<User, TKey> key)
{
return source.Where(x => key(x) != null && key(x).ToString() != string.Empty).Select(x => key(x)).Distinct().ToList();
}
I have an extension method to get a property name as string:
public static string GetPropertyName<T, TResult>(this T obj, Expression<Func<T, TResult>> propertyId)
{
return ((MemberExpression)propertyId.Body).Member.Name;
}
Now I have another method, expecting to pass in list (param) of this kind of property lamba expression.
I want this new method to reuse the 1st method, but can't figure out how to pass it over
public string Test<T>(params Expression<Func<T, object>>[] ps)
{
foreach (var p in ps)
{
var howToCodeThis = p.GetPropertyName(dummy => dummy);
expected usage:
var result = Test<Something>(request.Sorting
, x => x.prop1
, x => x.prop2
, x => x.prop3
);
Update:
Backs answer worked once I change my GetPropertyName to cater for UnaryExpression:
public static string GetPropertyName<T, TResult>(this T obj, Expression<Func<T, TResult>> propertyId)
{
if (propertyId.Body is MemberExpression)
return ((MemberExpression)propertyId.Body).Member.Name;
if (propertyId.Body is UnaryExpression)
{
var op = ((UnaryExpression)propertyId.Body).Operand;
return ((MemberExpression)op).Member.Name;
}
throw new NotImplementedException(string.Format("GetPropertyName - {0}", propertyId.Body.GetType().FullName));
}
var howToCodeThis = GetPropertyName(default(T), p);
OR
var howToCodeThis = default(T).GetPropertyName(p);
But I noteced, you don't use obj in GetPropertyName method.
Below is an example of a class that, searches an item in a DataGrid for text matches in it's property values. I currently call it with:
FullTextSearchNext<UserViewModel>.FullTextSearchInit();
The <UserViewModel> hardcoded above is what the ItemsSource in my DataGrid consists of. To clarify: the collection is made up of UserViewModel items.
What I am wondering is, is there a way I can get the item class (UserViewModel) from the DataGrid and replace the hardcoded <UserViewModel> with a variable of some sort? Thus making my calls to the ClassPropertySearch generic as well as the class itself.
public static class ClassPropertySearch<T>
{
public static bool Match(T item, string searchTerm)
{
bool match = _properties.Select(prop => prop(item)).Any(value => value != null && value.ToLower().Contains(searchTerm.ToLower()));
return match;
}
private static List<Func<T, string>> _properties;
public static void FullTextSearchInit()
{
_properties = GetPropertyFunctions().ToList();
}
}
[EDIT]
This is to show more of the class, which I should have done initially.
Includes Marius'solution:
Now that <T> is removed from ClassPropertySearch the other functions such as GetPropertyFunctions, etc, do not work , should I just pass the type through to them as parameters?
public static class ClassPropertySearch
{
public static bool Match(Type itemType, string searchTerm)
{
bool match = _properties.Select(prop => prop(itemType)).Any(value => value != null && value.ToLower().Contains(searchTerm.ToLower()));
return match;
}
private static List<Func<Type, string>> _properties;
public static void FullTextSearchInit(List<string> binding_properties)
{
_properties = GetPropertyFunctions().ToList();
}
public static IEnumerable<Func<Type, string>> GetPropertyFunctions()
{
return GetStringPropertyFunctions();
}
public static IEnumerable<Func<Type, string>> GetStringPropertyFunctions()
{
var propertyInfos = typeof(Type).GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)
.Where(p => p.PropertyType == typeof(string)).ToList();
var properties = propertyInfos.Select(GetStringPropertyFunc);
return properties;
}
public static Func<Type, string> GetStringPropertyFunc(PropertyInfo propInfo)
{
ParameterExpression x = System.Linq.Expressions.Expression.Parameter(typeof(Type), "x");
Expression<Func<Type, string>> expression = System.Linq.Expressions.Expression.Lambda<Func<Type, string>>(System.Linq.Expressions.Expression.Property(x, propInfo), x);
Func<Type, string> propertyAccessor = expression.Compile();
return propertyAccessor;
}
}
You could replace the generic type T with type Type.
public static class ClassPropertySearch
{
public static bool Match(Type itemType, string searchTerm)
{
bool match = _properties.Select(prop => prop(itemType)).Any(value => value != null && value.ToLower().Contains(searchTerm.ToLower()));
return match;
}
private static List<Func<Type, string>> _properties;
public static void FullTextSearchInit()
{
_properties = GetPropertyFunctions().ToList();
}
}
So instead of passing the UserViewModel you would pass typeof(UserViewModel). Of course, since you need this at runtime, you need to say obj.GetType().
I'm searching a way to store a collection of Expression<Func<T, TProperty>> used to order elements, and then to execute the stored list against a IQueryable<T> object (the underlying provider is Entity Framework).
For example, I would like to do something like this (this is pseudo code):
public class Program
{
public static void Main(string[] args)
{
OrderClause<User> orderBys = new OrderClause<User>();
orderBys.AddOrderBy(u => u.Firstname);
orderBys.AddOrderBy(u => u.Lastname);
orderBys.AddOrderBy(u => u.Age);
Repository<User> userRepository = new Repository<User>();
IEnumerable<User> result = userRepository.Query(orderBys.OrderByClauses);
}
}
An order by clause (property on which to order):
public class OrderClause<T>
{
public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
{
_list.Add(orderBySelector);
}
public IEnumerable<Expression<Func<T, ???>>> OrderByClauses
{
get { return _list; }
}
}
A repository with my query method:
public class Repository<T>
{
public IEnumerable<T> Query(IEnumerable<OrderClause<T>> clauses)
{
foreach (OrderClause<T, ???> clause in clauses)
{
_query = _query.OrderBy(clause);
}
return _query.ToList();
}
}
My first idea was to convert the Expression<Func<T, TProperty>> into a string (the property name on which to sort). So basically, instead of storing a typed list (which is not possible because the TProperty is not constant), I store a list of string with the properties to sort on.
But this doesn't work because then I cannot reconstruct the Expression back (I need it because IQueryable.OrderBy takes a Expression<Func<T, TKey>> as parameter).
I also tried to dynamically create the Expression (with the help of Expression.Convert), to have a Expression<Func<T, object>> but then I got an exception from entity framework that said that it was not able to handle the Expression.Convert statement.
If possible, I do not want to use an external library like the Dynamic Linq Library.
This is one of the few cases where a dynamic / reflection solution may be appropriate.
I think you want something like this? (I've read between the lines and made some changes to your structure where I thought necessary).
public class OrderClauseList<T>
{
private readonly List<LambdaExpression> _list = new List<LambdaExpression>();
public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
{
_list.Add(orderBySelector);
}
public IEnumerable<LambdaExpression> OrderByClauses
{
get { return _list; }
}
}
public class Repository<T>
{
private IQueryable<T> _source = ... // Don't know how this works
public IEnumerable<T> Query(OrderClause<T> clauseList)
{
// Needs validation, e.g. null-reference or empty clause-list.
var clauses = clauseList.OrderByClauses;
IOrderedQueryable<T> result = Queryable.OrderBy(_source,
(dynamic)clauses.First());
foreach (var clause in clauses.Skip(1))
{
result = Queryable.ThenBy(result, (dynamic)clause);
}
return result.ToList();
}
}
The key trick is getting C# dynamic to do the horrible overload resolution and type-inference for us. What's more, I believe the above, despite the use of dynamic, is actually type-safe!
One way to do this would be to “store” all the sort clauses in something like Func<IQueryable<T>, IOrderedQueryable<T>> (that is, a function that calls the sorting methods):
public class OrderClause<T>
{
private Func<IQueryable<T>, IOrderedQueryable<T>> m_orderingFunction;
public void AddOrderBy<TProperty>(Expression<Func<T, TProperty>> orderBySelector)
{
if (m_orderingFunction == null)
{
m_orderingFunction = q => q.OrderBy(orderBySelector);
}
else
{
// required so that m_orderingFunction doesn't reference itself
var orderingFunction = m_orderingFunction;
m_orderingFunction = q => orderingFunction(q).ThenBy(orderBySelector);
}
}
public IQueryable<T> Order(IQueryable<T> source)
{
if (m_orderingFunction == null)
return source;
return m_orderingFunction(source);
}
}
This way, you don't have to deal with reflection or dynamic, all this code is type safe and relatively easy to understand.
You can store your lambda expressions in a collection as instances of the LambdaExpression type.
Or even better, store sort definitions, each of which, in addition to an expression, aslo stores a sorting direction.
Suppose you have the following extension method
public static IQueryable<T> OrderBy<T>(
this IQueryable<T> source,
SortDefinition sortDefinition) where T : class
{
MethodInfo method;
Type sortKeyType = sortDefinition.Expression.ReturnType;
if (sortDefinition.Direction == SortDirection.Ascending)
{
method = MethodHelper.OrderBy.MakeGenericMethod(
typeof(T),
sortKeyType);
}
else
{
method = MethodHelper.OrderByDescending.MakeGenericMethod(
typeof(T),
sortKeyType);
}
var result = (IQueryable<T>)method.Invoke(
null,
new object[] { source, sortDefinition.Expression });
return result;
}
and a similar method for ThenBy. Then you can do something like
myQueryable = myQueryable.OrderBy(sortDefinitions.First());
myQueryable = sortDefinitions.Skip(1).Aggregate(
myQueryable,
(current, sortDefinition) => current.ThenBy(sortDefinition));
Here are the definitions of SortDefinition and MethodHelper
public class SortDefinition
{
public SortDirection Direction
{
get;
set;
}
public LambdaExpression Expression
{
get;
set;
}
}
internal static class MethodHelper
{
static MethodHelper()
{
OrderBy = GetOrderByMethod();
ThenBy = GetThenByMethod();
OrderByDescending = GetOrderByDescendingMethod();
ThenByDescending = GetThenByDescendingMethod();
}
public static MethodInfo OrderBy
{
get;
private set;
}
public static MethodInfo ThenBy
{
get;
private set;
}
public static MethodInfo OrderByDescending
{
get;
private set;
}
public static MethodInfo ThenByDescending
{
get;
private set;
}
private static MethodInfo GetOrderByMethod()
{
Expression<Func<IQueryable<object>, IOrderedQueryable<object>>> expr =
q => q.OrderBy((Expression<Func<object, object>>)null);
return ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
}
private static MethodInfo GetThenByMethod()
{
Expression<Func<IOrderedQueryable<object>, IOrderedQueryable<object>>> expr =
q => q.ThenBy((Expression<Func<object, object>>)null);
return ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
}
private static MethodInfo GetOrderByDescendingMethod()
{
Expression<Func<IQueryable<object>, IOrderedQueryable<object>>> expr =
q => q.OrderByDescending((Expression<Func<object, object>>)null);
return ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
}
private static MethodInfo GetThenByDescendingMethod()
{
Expression<Func<IOrderedQueryable<object>, IOrderedQueryable<object>>> expr =
q => q.ThenByDescending((Expression<Func<object, object>>)null);
return ((MethodCallExpression)expr.Body).Method.GetGenericMethodDefinition();
}
}
in E.F. Core you could use the following helper class
public static class OrderBuilder
{
public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> queryable, params Tuple<Expression<Func<TSource, object>>, bool>[] keySelectors)
{
if (keySelectors == null || keySelectors.Length == 0) return queryable;
return keySelectors.Aggregate(queryable, (current, keySelector) => keySelector.Item2 ? current.OrderDescending(keySelector.Item1) : current.Order(keySelector.Item1));
}
private static bool IsOrdered<TSource>(this IQueryable<TSource> queryable)
{
if (queryable == null) throw new ArgumentNullException(nameof(queryable));
return queryable.Expression.Type == typeof(IOrderedQueryable<TSource>);
}
private static IQueryable<TSource> Order<TSource, TKey>(this IQueryable<TSource> queryable, Expression<Func<TSource, TKey>> keySelector)
{
if (!queryable.IsOrdered()) return queryable.OrderBy(keySelector);
var orderedQuery = queryable as IOrderedQueryable<TSource>;
return (orderedQuery ?? throw new InvalidOperationException()).ThenBy(keySelector);
}
private static IQueryable<TSource> OrderDescending<TSource, TKey>(this IQueryable<TSource> queryable, Expression<Func<TSource, TKey>> keySelector)
{
if (!queryable.IsOrdered()) return queryable.OrderByDescending(keySelector);
var orderedQuery = queryable as IOrderedQueryable<TSource>;
return (orderedQuery ?? throw new InvalidOperationException()).ThenByDescending(keySelector);
}
}
and then use it as.. this example below with a class named Player with the following members..(code reduced for brevity)
public class Player
{
...
public string FirstName { get; set;
public int GenderTypeId { get; set; }
public int PlayingExperience { get; set; }
You could combine the orderings as you like, sorting by gender, playing experience descending (notice the true value of the tuple), and first name..
var combinedOrder = new[]
{
new Tuple<Expression<Func<Player, object>>, bool>(p => p.GenderTypeId, false),
new Tuple<Expression<Func<Player, object>>, bool>(p => p.PlayingExperience, true),
new Tuple<Expression<Func<Player, object>>, bool>(p => p.FirstName, false),
};
and just do the order as follows
var data = context.Set<Player>()
.OrderBy(combinedOrder)
.ToArray();