Passing a Func<T, TResult> where TResult is unknown - c#

Note: Please re-tag and/or re-name appropriately
I have a class, FooEnumerator, that wraps a Foo and implements IEnumerable<FooEnumerator>. The Foos represent a tree-like data structure, the FooEnumerators that are enumerated are the child nodes of the current node.
Foo is a vendor supplied data object. FooEnumerator implements a bunch of custom filtering code.
class FooEnumerator : IEnumerable<FooEnumerator>
{
public Foo WrappedNode { get; private set; }
public string Name { get { return WrappedNode.Name; } }
public int Id { get{ return WrappedNode.Id; } }
public DateTime Created { get{ return WrappedNode.Created; } }
public FooEnumerator(Foo wrappedNode)
{
WrappedNode = wrappedNode;
}
public IEnumerator<FooEnumerator> GetEnumerator()
{
foreach (Foo child in this.GetChildren())
if(FilteringLogicInHere(child))
yield return new FooEnumerator(child);
}
...
}
I want to be able to sort each level of the tree with a given (arbitrary) expression, defined when the top level FooEnumerator is created, and have this expression passed down to each newly enumerated item to use.
I'd like to define the sort expression using lambda's, in the same way you would with the OrderBy function. In fact, it is my intention to pass the lambda to OrderBy.
The signiture for OrderBy is
OrderBy<TSource, TKey>(Func<TSource, TKey> keySelector)
where TKey is the return type of the given Func, but is a Type Parameter in the method signature and is figured out at compile time.
Example usage
var x = GetStartingNode();
var sort = n => n.DateTime;
var enu = new FooEnumerator(x, sort);
var sort2 = n => n.Name;
var enu2 = new FooEnumerator(x, sort2);
The sort expression would then be stored in a class variable and FooEnumerator would work like:
// pseudo-implementation
private Expression<Func<Foo, TKey>> _sortBy;
public FooEnumerator(Foo wrappedNode, Expression<Func<Foo, TKey>> sortBy)
{
WrappedNode = wrappedNode;
_sortBy = sortBy;
}
public IEnumerator<FooEnumerator> GetEnumerator()
{
foreach (Foo child in this.GetChildren().OrderBy(_sortBy))
if(FilteringLogicInHere(child))
yield return new FooEnumerator(child);
}
How can I specify the type of TKey (implicitly or explicitly) in this use case?
I don't want to hard code it as I want to be able to sort on any and all properties of the underlying Foo.

Well, you can't create a member delegate variable of type Expression<Func<Foo,TKey>> since TKey is never specified. However, you could create a member of type Expression<Func<Foo,IComparable>> which may suffice for your purposes. You could need to change your FooEnumerator constructor to accept this signature as well, of course.
EDIT: Others have suggested parameterizing your FooEnumerator so that it accepts a TKey. You can certainly do this, but you should be aware of the issues that emerge:
By parameterizing the enumerator you are then kicking the bucket down the road. Any code that wants to store a FooEnumerator<T> has to have a-priori knowledge of the type T. You could, however, implement a non-generic interface IFooEnumerator to deal with that.
Parameterizing an enumerator creates issues if you want to support ordering on multiple fields in the future. C# doesn't support generics with a variable number of type parameters, which limits the creation of generics that require multiple arbitrary types. This issue is harder to deal with, since it's awkward to start creating FooEnumerator<T>, FooEnumerator<T1,T2>, FooEnumerator<T1,T2,T3...>, and so on.

You can also parameterize your Enumerator:
class FooEnumerator<TKey> {
// ... All your 'pseudo' code would work here
}
I recommend programming against the interface using IComparable however.

Related

Re-implementation of OrderBy, ThenBy and Null TypeMapping in Sql Tree error

I am trying to implement OrderBy and ThenBy in a different way to hide lambda expression from OrderBy and ThenBy extension methods. These extension methods accept classes which implement IOrderSpecification:
public class PersonOrderByAgeSpecification : OrderSpecification<Person>
{
public PersonOrderByAgeSpecification(Sort direction= Sort.Ascending) : base(direction)
{
}
public override Expression<Func<Person, IComparable>> AsExpression()
{
return personOrder => personOrder.Age;
}
}
And the usage:
var orderSpecification = new PersonOrderByAgeSpecification(Sort.Ascending);
var sortedPeople= _dbContext.People.OrderBy(orderSpecification);
It works fine when the property type in AsExpression() is just string. For example:
public override Expression<Func<Person, IComparable>> AsExpression()
{
return personOrder => personOrder.FirstName;
}
Otherwise I would get this error: (Does not work with integer or bool)
InvalidOperationException: Null TypeMapping in Sql Tree
Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.RelationalSqlTranslatingExpressionVisitor+SqlTypeMappingVerifyingExpressionVisitor.VisitExtension(Expression
node)
The source code is available here
I appreciate any help.
First off, you are using preview (beta) software, which is expected to have issues.
But the main problem is that LINQ ordering methods have second generic type argument TKey, which you are hiding behind IComparable, which for value types causes a hidden cast inside the expression.
Apart from unnecessary boxing, this is not a problem for LINQ to Objects provider because it simply compiles and executes a delegate from the lambda expression. However other IQueryable providers usually need to translate the expression to something else (usually SQL). Most of them identify such casts (Expression.Convert) and remove them during the processing. Apparently EF 3.0 preview you are using doesn't, hence the exception.
You can avoid such issues by eliminating the hidden casts yourself. It's possible to do that with expression manipulation, but the easiest is to introduce the second generic type argument to your base abstract class:
public abstract class OrderSpecification<T, TKey> : IOrderSpecification<T>
and change the abstract method signature to
public abstract Expression<Func<T, TKey>> AsExpression();
The implementation, interface and everything else except the concrete classes will remain as is.
Now all you need is to specify the actual key type in the inherited class and change the AsExpression override signature. For instance:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class PersonAgeOrderSpecification : OrderSpecification<Person, int>
{
public PersonAgeOrderSpecification(Sort direction) : base(direction) { }
public override Expression<Func<Person, int>> AsExpression()
{
return person => person.Age;
}
}
and everything will be fine.

Use IQueryable.OrderBy for a composite key without loading all the items?

I am retrieving some tuples from a database that are mapped to entity classes by means of Entity Framework.
For these entities, I have a key selector function (supplied at runtime by other developers) that I would like to pass to Queryable.OrderBy. The key selector function is provided upon "registration" of the entity type in my system - which happens by means of a method that looks roughly like this:
public void RegisterEntity<TEntity, TKey>(string entityName, TKey defaultKey, Func<TEntity, TKey> keySelectorFunc)
I would like to execute this OrderBy call before materializing the results to entity objects (i.e. in such a way that the OrderBy call still gets translated to SQL under the hood).
The problem is that the entities have composite keys, and thus, the key selector function will return a custom object instantiated in the function. You can imagine it like this:
var keySelectorFunc = e => new CustomKey(e.Value1, e.Value2);
As usual, Entity Framework does not like this (the usual "Only parameterless constructors and initializers are supported in LINQ to Entities" error).
Is there any way to use such a custom key selector function to return a custom key? Do I have to resort to anonymous classes? Or should I move the OrderBy call to a place after I have left the LINQ-to-Entities world?
In this particular case it would be easy to use Sort method of Generic List.
https://msdn.microsoft.com/en-us/library/3da4abas(v=vs.110).aspx
Sort method requires the type of the list to implement IComparable interface and it uses the implementation of CompareTo method from IComparable interface. Otherwise implementation of IComparer also can be passed to this method.
So if your entity class is already implemeting IComparable interface then this should surely work for you. You will have to to .ToList() on the IQueryable result of course before you can call the Sort method on it.
public class Category : IComparable<Category>
{
public int CategoryId { get; internal set; }
public string CategoryName { get; internal set; }
public int CompareTo(Category x)
{
return String.Compare(x.CategoryName, this.CategoryName, StringComparison.InvariantCulture);
}
}
List<Category> categories = new List<Category>();
categories.Add(new Category {CategoryName = "Cate1"});
categories.Add(new Category {CategoryName = "Cate2"});
categories.Sort();
foreach (var cat in categories)
{
Console.WriteLine(cat.CategoryName);
}
This displays me category names in reverse order based on the comparison logic I have written in the CompareTo method of Category Class.
In this case I think the best way is use a custom ExtensionMethod to avoid any overhead of coding or unnecessary complexity to do that.
See if it implementation can help you.
First we create your customkey class that is responsable to create the statement expressions:
class CustomKey
{
public CustomKey(params string[] value)
{
if(!value.Any())
throw new InvalidOperationException("Select at least one Property for this operation");
Values = new List<string>();
Values.AddRange(value);
}
private List<string> Values { get; set; }
// this method run throughout all property configured to create the expressions
public void ForEachProperty<TSource, TKey>(Action<Expression<Func<TSource, TKey>>, bool> method)
{
bool firstItem = true;
Values.ForEach(f =>
{
var expression = CreateExpression<TSource, TKey>(f);
method(expression, firstItem);
firstItem = false;
});
}
// this method is responsable to create each expression
Expression<Func<TSource, TKey>> CreateExpression<TSource, TKey>(string property)
{
var parameter = Expression.Parameter(typeof(TSource), "x");
var member = typeof(TSource).GetMember(property).FirstOrDefault();
Expression body = Expression.MakeMemberAccess(parameter, member);
return Expression.Lambda<Func<TSource, TKey>>(Expression.Convert(body, typeof(object)), parameter);
}
}
After that we create your custom ExtesionMethod, somethink like that:
public static class OrderByExtensionClass
{
// instead of try passing an expression, we pass our CustomKey object with the columns to sort.
// than this method create the apropriate OrderBy Expression statement
public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, CustomKey customKey)
{
// the parameter isFirst is just to control where we are to build the expression
customKey.ForEachProperty<TSource, object>((expression, isFirst) =>
{
if (isFirst)
source = source.OrderBy(expression);
else
source = ((IOrderedQueryable<TSource>)source).ThenBy(expression);
});
return ((IOrderedQueryable<TSource>)source);
}
}
After that we just do:
CustomKey custom = new CustomKey("Name", "Age");
myEntityContext.People.OrderBy(custom).ToList()
I hope it can help you.
Part of the problem, I think, is that OrderBy wouldn't know what to do with a complex type. SQL Server knows how to order by primitive types, but that's about it. You would have to do something like ...OrderBy(x=>x.Field1).ThenBy(x=>x.Field2). You could write an extension method that takes the key, extracts the property names from the key, and builds the .OrderBy().ThenBy() expression, as long as you know what the key will be before executing the query. Otherwise yeah, you may have to materialize the results before ordering.

Is there a built-in generic interface with covariant type parameter returned by an indexer?

In this thread
How to get null instead of the KeyNotFoundException accessing Dictionary value by key?
in my own answer I used explicit interface implementation to change the basic dictionary indexer behaviour not to throw KeyNotFoundException if the key was not present in the dictionary (since it was convinient for me to obtain null in such a case right inline).
Here it is:
public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}
public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
if (ContainsKey(key))
return this[key];
else
return null;
}
}
}
Since in a real application I had a list of dictionaries, I needed a way to access the dictionaries from the collection as an interface. I used simple int indexer to acess each element of the list.
var list = new List<NullValueDictionary<string, string>>();
int index = 0;
//...
list[index]["somekey"] = "somevalue";
The easiest thing was to do something like this:
var idict = (INullValueDictionary<string, string>)list[index];
string value = idict["somekey"];
The question raised when I decided to try to use covariance feature to have a collection of interfaces to use instead. So I needed an interface with covariant type parameter for the cast to work. The 1st thing that came to my mind was IEnumerable<T>, so the code would look like this:
IEnumerable<INullValueDictionary<string, string>> ilist = list;
string value = ilist.ElementAt(index)["somekey"];
Not that nice at all, besides ElementAt instead of an indexer is way worse.
The indexer for List<T> is defined in IList<T>, and T there is not covariant.
What was I to do? I decided to write my own:
public interface IIndexedEnumerable<out T>
{
T this[int index] { get; }
}
public class ExtendedList<T> : List<T>, IIndexedEnumerable<T>
{
}
Well, few lines of code (I don't even need to write anything in ExtendedList<T>), and it works as I wanted:
var elist = new ExtendedList<NullValueDictionary<string, string>>();
IIndexedEnumerable<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = ielist[index]["somekey"];
Finally the question: can this covariant cast be somehow achieved without creating an extra collection?
You can try use IReadOnlyList<T>, which is implemented by List<T>.
Note that I've added one instance of NullValueDictionary<string, string> to List, so that you won't get ArgumentOutOfRangeException at elist[index] line.
IReadOnlyList<NullValueDictionary<string, string>> elist = new List<NullValueDictionary<string, string>>
{
new NullValueDictionary<string, string>()
};
IReadOnlyList<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = elist[index]["somekey"];
Edit: I've searched for covariant interfaces and collections with indexes prior to .NET 4.5, but found none. Still I think there are a little bit easier solution, than to create separate interface - just to cast one collection to another.
List<INullValueDictionary<string, string>> ielist = elist.Cast<INullValueDictionary<string, string>>().ToList();
Or use covariance gained from arrays
INullValueDictionary<string, string>[] ielist = elist.ToArray()
LINQ has some optimization that work on whole type compatibility, so you won't iterate over sequence if those types are compatible.
Cast implementation taken from MONO Linq
public static IEnumerable<TResult> Cast<TResult> (this IEnumerable source)
{
var actual = source as IEnumerable<TResult>;
if (actual != null)
return actual;
return CreateCastIterator<TResult> (source);
}
Note that I have changed INullValueDictionary<T, U> interface to contain set in the property so that ielist[index]["somekey"] = "somevalue"; will work.
public interface INullValueDictionary<T, U> where U : class
{
U this[T key] { get; set; }
}
But again - if creating a new Interface and class is ok for you and you don't want to mess around with casts everywhere - I think it is a good solution, if you have considered at the constraints, it gives.
In search of covariance in mscorlib
This probably won't be interesting to you, but I've just wanted to find out what Types are covariant in mscorlib assembly. By running next script I received only 17 types are covariant, 9 of which are Funcs. I have omitted IsCovariant implementation, because this answer is too long even without it
typeof(int).Assembly.GetTypes()
.Where(type => type.IsGenericType)
.Where(type=>type.GetGenericArguments().Any(IsCovariant))
.Select(type => type.Name)
.Dump();
//Converter`2
//IEnumerator`1
//IEnumerable`1
//IReadOnlyCollection`1
//IReadOnlyList`1
//IObservable`1
//Indexer_Get_Delegate`1
//GetEnumerator_Delegate`1

Passing lambda expression as parameter

I've got a few tables that all have the same column domainID which basically just controls what data gets displayed on which website, as they share a database.
So when I go to databind a table to a control I would need to create a large switch to handle the different LINQ queries. I would like to create a utility method which takes the table type as a parameter and then return a where clause based on a column in passed table.
public static IEnumerable<T> ExecuteInContext<T>(
IQueryable<T> src)
{
int domain = 1;//hard coded for example
return src.Where(x => x.DomainID == domain);//Won't work, has to be a way to do this.
}
I'm stuck on the return code. You can't simply construct a where clause like I currently am because it doesn't know what table i'm talking about.
I'm trying to call that first method like this:
using (DataClasses1DataContext db = new DataClasses1DataContext())
{
var q = Utility.ExecuteInContext(db.GetTable<item>());
Repeater1.DataSource = q;
Repeater1.DataBind();
}
I hope this explains what I'm trying to do.
Edit: BrokenGlass's answer solved my problem. I would like to add that you need to open up your .dbml.cs file and extend the table/class with your interface. I also wanted to point out that the project wouldn't build if my column was nullable, it said it wasn't the same return type as my interface.
You have to restrict your T to a class that has a property of DomainID - you can add these interface implementations in partial classes that extend your data model.
public interface IFoo
{
int DomainId { get; set; }
}
..
public static IQueryable<T> ExecuteInContext<T>(IQueryable<T> src) where T: IFoo
{
int domain = 1;//hard coded for example
return src.Where(x => x.DomainID == domain);
}
Expression pe = Expression.Parameter(typeof(T));
Expression prope = Expression.Property(pe, "DomainID");
Expression ce = Expression.Equals(prope,
Expression.Constant((int)1);
Expression<Func<T,bool>> exp =
Expression.Lambda<Func<T,bool>>(
ce, pe);
return query.Where(exp);
You should be able to cast your generic parameter to the intended type...
public static IEnumerable<T> ExecuteInContext<T>(IQueryable<T> src)
{
int domain = 1;//hard coded for example
return src.Where(x => ((T)x).DomainID == domain);
}
But you realize you've created a generic method that assumes its type parameter will always expose a specific property? If you're going to do that, you should apply a generic type constraint such that T is always derived from a type that has that property...
For example:
public static IEnumerable<T> ExecuteInContext<T>(IQueryable<T> src) where T : IMyDomainObject
I'm not sure if I understand what you mean, but maybe you want to add a where clause:
public static IEnumerable<T> ExecuteInContext<T>(IQueryable<T> src)
where T: MyType //MyType exposing your DomainId
{
int domain = 1;//hard coded for example
return src.Where(x => x.DomainID == domain);//Won't work, has to be a way to do this.
}

How can I implement NotOfType<T> in LINQ that has a nice calling syntax?

I'm trying to come up with an implementation for NotOfType, which has a readable call syntax. NotOfType should be the complement to OfType<T> and would consequently yield all elements that are not of type T
My goal was to implement a method which would be called just like OfType<T>, like in the last line of this snippet:
public abstract class Animal {}
public class Monkey : Animal {}
public class Giraffe : Animal {}
public class Lion : Animal {}
var monkey = new Monkey();
var giraffe = new Giraffe();
var lion = new Lion();
IEnumerable<Animal> animals = new Animal[] { monkey, giraffe, lion };
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>();
However, I can not come up with an implementation that supports that specific calling syntax.
This is what I've tried so far:
public static class EnumerableExtensions
{
public static IEnumerable<T> NotOfType<T>(this IEnumerable<T> sequence, Type type)
{
return sequence.Where(x => x.GetType() != type);
}
public static IEnumerable<T> NotOfType<T, TExclude>(this IEnumerable<T> sequence)
{
return sequence.Where(x => !(x is TExclude));
}
}
Calling these methods would look like this:
// Animal is inferred
IEnumerable<Animal> fewerAnimals = animals.NotOfType(typeof(Giraffe));
and
// Not all types could be inferred, so I have to state all types explicitly
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Animal, Giraffe>();
I think that there are major drawbacks with the style of both of these calls. The first one suffers from a redundant "of type/type of" construct, and the second one just doesn't make sense (do I want a list of animals that are neither Animals nor Giraffes?).
So, is there a way to accomplish what I want? If not, could it be possible in future versions of the language? (I'm thinking that maybe one day we will have named type arguments, or that we only need to explicitly supply type arguments that can't be inferred?)
Or am I just being silly?
I am not sure why you don't just say:
animals.Where(x => !(x is Giraffe));
This seems perfectly readable to me. It is certainly more straight-forward to me than animals.NotOfType<Animal, Giraffe>() which would confuse me if I came across it... the first would never confuse me since it is immediately readable.
If you wanted a fluent interface, I suppose you could also do something like this with an extension method predicate on Object:
animals.Where(x => x.NotOfType<Giraffe>())
How about
animals.NotOf(typeof(Giraffe));
Alternatively, you can split the generic parameters across two methods:
animals.NotOf().Type<Giraffe>();
public static NotOfHolder<TSource> NotOf<TSource>(this IEnumerable<TSource> source);
public class NotOfHolder<TSource> : IHideObjectMembers {
public IEnumerable<TSource> NotOf<TNot>();
}
Also, you need to decide whether to also exclude inherited types.
This might seem like a strange suggestion, but what about an extension method on plain old IEnumerable? This would mirror the signature of OfType<T>, and it would also eliminate the issue of the redundant <T, TExclude> type parameters.
I would also argue that if you have a strongly-typed sequence already, there is very little reason for a special NotOfType<T> method; it seems a lot more potentially useful (in my mind) to exclude a specific type from a sequence of arbitrary type... or let me put it this way: if you're dealing with an IEnumerable<T>, it's trivial to call Where(x => !(x is T)); the usefulness of a method like NotOfType<T> becomes more questionable in this case.
If you're going to make a method for inference, you want to infer all the way. That requires an example of each type:
public static class ExtMethods
{
public static IEnumerable<T> NotOfType<T, U>(this IEnumerable<T> source)
{
return source.Where(t => !(t is U));
}
// helper method for type inference by example
public static IEnumerable<T> NotOfSameType<T, U>(
this IEnumerable<T> source,
U example)
{
return source.NotOfType<T, U>();
}
}
called by
List<ValueType> items = new List<ValueType>() { 1, 1.0m, 1.0 };
IEnumerable<ValueType> result = items.NotOfSameType(2);
I had a similar problem, and came across this question whilst looking for an answer.
I instead settled for the following calling syntax:
var fewerAnimals = animals.Except(animals.OfType<Giraffe>());
It has the disadvantage that it enumerates the collection twice (so cannot be used with an infinite series), but the advantage that no new helper function is required, and the meaning is clear.
In my actual use case, I also ended up adding a .Where(...) after the .OfType<Giraffe>() (giraffes also included unless they meet a particular exclusion condition that only makes sense for giraffes)
I've just tried this and it works...
public static IEnumerable<TResult> NotOfType<TExclude, TResult>(this IEnumerable<TResult> sequence)
=> sequence.Where(x => !(x is TExclude));
Am I missing something?
You might consider this
public static IEnumerable NotOfType<TResult>(this IEnumerable source)
{
Type type = typeof(Type);
foreach (var item in source)
{
if (type != item.GetType())
{
yield return item;
}
}
}

Categories