Any significant reason to avoid `as IQueryable`? - c#

I have a library of model-to-viewmodel mapping extension methods. Supporting them is a base class with a few common methods, including Transform, below:
internal abstract class TransformBase<TOriginal, TConverted>
{
protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }
public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
{
var queryable = value as IQueryable<TOriginal> ?? value.AsQueryable();
return queryable.Select(Expression);
}
My question: is there any significant reason, besides a negligible performance hit, that I should avoid the as IQueryable cast above? For example, I could instead do the following:
internal abstract class TransformBase<TOriginal, TConverted>
{
protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }
public IQueryable<TConverted> Transform(IQueryable<TOriginal> value)
{
return value.Select(Expression);
}
public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
{
return value.AsQueryable().Select(Expression);
}
... but I would prefer not to have to write the overloads in every one of my dependent classes. EDIT: To clarify, here is an example of what I'm seeking to avoid:
public static class TransformCompany
{
private static readonly TransformBase<Organization, CompanyHeader> header = new TransformPrecompiled<Organization, CompanyHeader>(
company => new CompanyHeader
{
Name = company.Name,
});
public static IQueryable<CompanyHeader> AsHeaders(this IQueryable<Organization> companies)
{
return header.Transform(companies);
}
// Note I have to include this capability in each of my dependent classes
// Worse is the possibility that someone may accidentally implement
// only IEnumerable for a future model transformation,
// causing a hidden data performance problem
public static IQueryable<CompanyHeader> AsHeaders(this IEnumerable<Organization> companies)
{
return header.Transform(companies);
}

I would say you do not need separate extensions for IEnumerable<T> and IQueryable<T> as IQueryable<T> inherits from IEnumerable<T>, and you also do not need to the cast.
Looking at referencesource, AsQueryable() actually does this check for you:
public static IQueryable<TElement> AsQueryable<TElement>(this IEnumerable<TElement> source)
{
if (source == null)
throw Error.ArgumentNull("source");
if (source is IQueryable<TElement>)
return (IQueryable<TElement>)source;
return new EnumerableQuery<TElement>(source);
}
Therefore the following should work for you with no performance hit:
internal abstract class TransformBase<TOriginal, TConverted>
{
protected abstract Expression<Func<TOriginal, TConverted>> Expression { get; }
public IQueryable<TConverted> Transform(IEnumerable<TOriginal> value)
{
return value.AsQueryable().Select(Expression);
}
}
public static class TransformCompany
{
public static IQueryable<CompanyHeader> AsHeaders(this IEnumerable<Organization> companies)
{
return header.Transform(companies);
}
}

Queryable.AsQueryable Method (IEnumerable)
If the type of source implements IQueryable,
AsQueryable(IEnumerable) returns it directly. Otherwise, it returns an
IQueryable that executes queries by calling the equivalent query
operator methods in Enumerable instead of those in Queryable.
Instead of casting you simplify your Transform method to
return value.AsQueryable().Select(Expression);

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.

Efficiently return IList<Interface> from List<T> (avoid casting from List<T> to List<I>)

I have the following code:
public interface ISomeObject
{
IList<ISomeObject> Objects { get; }
}
public class SomeObject : ISomeObject
{
public SomeObject()
{
Objects = new List<SomeObject>();
}
public List<SomeObject> Objects
{
get;
set;
}
IList<ISomeObject> ISomeObject.Objects
{
get
{
// What to do here?
// return Objects; // This doesn't work
return Objects.Cast<ISomeObject>().ToList(); // Works, but creates a copy each time.
}
}
SomeObject has a public property Objects that returns a List of class type. Clients knowing that class type can use that to do whatever they want. Clients only knowing about ISomeObject can use the Objects property only to get an IList<ISomeObject>. Because it is not allowed to cast List<SomeObject> to IList<ISomeObject> (due to the apple and banana issue) I need a way of converting that. The default way, using a Cast.ToList() works, but has the downside that it creates a new List each time the property is evaluated, which may be expensive. Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case). And using Linq's ElementAt() call repeatedly is expensive, when used on an IEnumerable.
Has anybody got an idea on how to avoid either problem?
(of course, making SomeObject known everywhere is not an option).
You could/should implement a class similar to ReadOnlyCollection<T> to act as a proxy. Considering that it would be read only, it could be "covariant" (not language-side, but logically, meaning that it could proxy a TDest that is a subclass/interface of TSource) and then throw NotSupportedException() for all the write methods.
Something like this (code untested):
public class CovariantReadOlyList<TSource, TDest> : IList<TDest>, IReadOnlyList<TDest> where TSource : class, TDest
{
private readonly IList<TSource> source;
public CovariantReadOlyList(IList<TSource> source)
{
this.source = source;
}
public TDest this[int index] { get => source[index]; set => throw new NotSupportedException(); }
public int Count => source.Count;
public bool IsReadOnly => true;
public void Add(TDest item) => throw new NotSupportedException();
public void Clear() => throw new NotSupportedException();
public bool Contains(TDest item) => IndexOf(item) != -1;
public void CopyTo(TDest[] array, int arrayIndex)
{
// Using the nuget package System.Runtime.CompilerServices.Unsafe
// source.CopyTo(Unsafe.As<TSource[]>(array), arrayIndex);
// We love to play with fire :-)
foreach (TSource ele in source)
{
array[arrayIndex] = ele;
arrayIndex++;
}
}
public IEnumerator<TDest> GetEnumerator() => ((IEnumerable<TDest>)source).GetEnumerator();
public int IndexOf(TDest item)
{
TSource item2 = item as TSource;
if (ReferenceEquals(item2, null) && !ReferenceEquals(item, null))
{
return -1;
}
return source.IndexOf(item2);
}
public void Insert(int index, TDest item)
{
throw new NotSupportedException();
}
public bool Remove(TDest item)
{
throw new NotSupportedException();
}
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Use it like:
IList<string> strs = new List<string>();
IList<object> objs = new CovariantReadOlyList<string, object>(strs);
Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case).
Indexing isn't just supported by the IList<T> interface, it's also supported by the IReadOnlyList<T> interface. Because IReadOnlyList<T> doesn't allow modification, it can be (and is) covariant just like IEnumerable<T> is.
So, just change the return type to IReadOnlyList<ISomeObject> and return the original list.
Of course, nothing prevents the caller from casting the result to List<SomeObject>, but the caller is supposed to have full access to that list anyway, so there is no security risk.
You may want try to encapsulate your List<SomeObject> making it an implementation detail and return IReadOnlyList<SomeObject> instead. Then SomeObject to ISomeObject cast want be unnecessary in interface implementation as well due to IReadOnlyList variance — you'll be able to return your Objects as IReadOnlyList<ISomeObject> .
Then just add some operations to mutate your underlying list like Add or Remove to container type if those are required.
Also I should mention that interfaces are not so good for restriction — evil consumer can easily cast your ISomeObject to SomeObject and do everything he wants, probably, you should reconsider your design. You'd better stick to such things as immutability and encapsulation for providing usable api. Explicitly use mutable builders then for immutable classes where it's reasonable.

Generic method how to return all of type T

say I have the following code:
public class Pond
{
public List<Frog> Frogs { get; set; }
public List<MudSkipper> MudSkippers { get; set; }
public List<Eel> Eels { get; set; }
}
public class Frog: IAquaticLife
{
}
public class MudSkipper: IAquaticLife
{
}
public class Eel: IAquaticLife
{
}
Now I want to write a generic method that will for a certain pond return the list of these types:
public IEnumerable<T> GetByPond<T>(int pondId) where T : IAquaticLife
{
return Uow.GetByID<Pond>(pondId).Eels;
}
Ok, so what I have there will return all the eels in that pond. What I was wanting to do was to return all the T's.
so if I called GetByPond<MudSkipper>(1) that would return all the mudskippers.
Anyone know how to do this?
How about something like
public IEnumerable<T> GetByPond<T>(int pondId) where T : IAquaticLife
{
return from t in Uow.GetByID<Pond>(pondId).AquaticLife()
where (typeof(t) == typeof(T)) select t;
}
or simply (using the approach that #DStanley pointed out before changing his answer)
public IEnumerable<T> GetByPond<T>(int pondId) where T : IAquaticLife
{
return Uow.GetByID<Pond>(pondId).AquaticLife().OfType<T>();
}
That requires Uow.GetByID(int id) to return all types of creatures in the particular pond that implement IAquaticLife. The alternative, though, is that you hard-code knowledge of the various implementers of IAquaticLife into your generic method. That is not a good idea.
UPDATE
Currently a Pond has separate collections for Eels, Mudskippers, etc. That becomes fragile if you want to add more things that implement IAquaticLife as your code evolves because you have to change both Pond and the generic method above.
I suggest that instead of separate methods for each type of aquatic life, you instead have a single method that returns everything in the pond that implements IAquaticLife, e.g.
public class Pond
{
public IEnumerable<IAquaticLife> AquaticLife() { ... }
}
I have updated my code above with this assumption.
Anyone that has a Pond instance and wants to get, say, just the Eels can do this:
var eels = pond.AquaticLife().OfType<Eels>();
Try this:
return Uow.GetByID<Pond>(pondId).OfType<T>();
EDIT
Since you've got the collections in separate properties, you could use either a switch block to return the right property based on the type, or use reflection to get the property based on the type name.
A better design based on your requirement would be to have a private List<IAquaticLife> that would store all of the critters instead of separate properties, but I'll assume that you can't do that right now.
An example of the switch would be:
public IEnumerable<T> GetByPond<T>(int pondId) where T : IAquaticLife
{
switch(typeof(T))
{
case typeof(Eel):
return Uow.GetByID<Pond>(pondId).Eels;
//etc.
default:
throw new ApplicationException(string.Format("No property of type {0} found",typeof(T).Name));
}
}
public Pond GetByPond(int pondId)
{
return Uow.GetByID<Pond>(pondId);
}
If you want your Frogs, do:
var frogs = xxx.GetByPond(1).Frogs;
If you want your MudSkippers, do:
var mudSkippers = xxx.GetByPond(1).MudSkippers;
And so on.
If you can call GetByPond<Frog>(1), you can call GetByPond(1).Frogs.
If in any case you don't know the T, you'll need to create a collection of all of them and filter them by the type. This is also useful if you have intermediate subtype:
public IEnumerable<T> GetByPond<T>(int pondId) where T : IAquaticLife
{
var pond = Uow.GetByID<Pond>(pondId);
var life = pond.Frogs.Union(pond.Eels).Union(pond.MudSkippers);
return life.OfType<T>();
}
But you are concatenating the collections just to filter them.

Multiple generic types in same list and calling their methods

I'm making an object validation framework in my spare time to learn a few things and maybe use it for some school projects.
I have my generic Rule class, which looks something like this :
class Rule<T>
{
string propertyName;
Func<T, bool> ruleLambda;
bool IsBroken(T value)
{
return ruleLambda(value);
}
}
An object that would be validated would look a bit like this :
class Example
{
List<Rule<?>> MyRules; // can take all types of rules
List<Rule<T>> Validate<T>(string propertyName, T value)
{
List<Rule<T>> brokenRules = new List<Rule<T>>();
foreach (Rule rule in MyRules.Where(r => r.propertyName == propertyName))
{
if (rule.IsBroken(value))
brokenRules.Add(rule);
}
return brokenRules;
}
}
Where the T value argument would be the value of one of the Example class's properties, which can be of any type.
The Validate<T> method is called whenever a property is set.
The problem lies with the class's list of rules. Specifically the List<Rule<?>> line above. I want to store all the rules for a given class in the same list.
Alas, C# doesn't have a wildcard for generic types like in Java.
How should I do this?
A non-generic interface or base class utilizing objects instead of T could work, but how would I call the generic Rule's IsBroken method and not the non-generic one?
I would store your rules as object inside the Example class and use Enumerable.OfType<T> to find the matching rules for a given type:
class Example
{
private List<object> rules;
List<Rule<T>> Validate<T>(string propertyName, T value)
{
return this.rules.OfType<Rule<T>>()
.Where(r => r.PropertyName == propertyName && r.IsBroken(value))
.ToList();
}
}
In cases where I've needed something like this, I use interfaces or non-generic base classes. For example, you could create an interface:
public interface IRule
{
//non-generic properties & methods
}
public class Rule<T> : IRule
{
//implementation
}
then create a list of the interfaces:
private List<IRule> MyRules;
If you want to make converting from the interface to the generic easy, you could add an extension method:
public static Rule<T> ToGeneric<T>(this IRule rule)
{
return rule as Rule<T>;
}
I've tried a few things and I've found something that works pretty well for my needs. I have Rule<T> inherit from a base abstract rule class, with a generic IsBroken method:
abstract class Rule
{
string propertyName;
Func<object, bool> objectRule;
bool IsBroken<T>(T value)
{
Rule<T> rule = this as Rule<T>;
if (rule == null)
return objectRule(value);
return rule.IsBroken(value);
}
}
As you can see, I try to convert the base class to its generic counterpart using the generic type parameter in the IsBroken method.
Also, when creating a Rule<T> instance, I send a Func<object, bool> to its base class protected constructor:
public Rule(string propertyName, Func<T, bool> ruleLambda)
: base(propertyName, ConvertToObjectFunc(ruleLambda))
{
}
With the conversion method looking like this:
static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>(o => func((T)o));
}
However, if it can't cast o to type T, it crashes. So I wrote this... thing:
static Func<object, bool> ConvertToObjectFunc(Func<T, bool> func)
{
return new Func<object, bool>
(
o =>
{
try
{
T obj = (T)o;
return func(obj);
}
catch { return true; } // rule is broken by default
}
);
}
It's pretty ugly, but it works. Hope this can help anybody else.

Extension method that works on IEnumerable<T> and IQueryable<T>?

I want an extension method that works on both my List and IQueryable. The extension methods below accomplish this, but then if I add another identical extension method, but on a different totally unrelated type I get ambiguous call
compile errors. Why is that? Isn't the compiler smart enough to know which extension method works? I mean, only one of these calls is valid, why can't the compiler tell? Thanks a lot!
class ClassA
{
public bool IsActive{ get; set;}
}
class ClassB
{
public bool IsActive { get; set;}
}
// then here are my extensions
public static T IsActive<T>(this T enumerableOrQueryable, bool isActive)
where T : IEnumerable<ClassA>
{
return (T)enumerableOrQueryable.Where(x => x.IsActive == isActive);
}
public static T IsActive<T>(this T enumerableOrQueryable, bool isActive)
where T : IEnumerable<ClassB>
{
return (T)enumerableOrQueryable.Where(x => x.IsActive == isActive);
}
The overload rules don't take account of the constraints on methods that it's considering - it determines which overload is best and then validates that the constraints match.
The compiler is exactly following the rules of the C# specification.
Related blog posts:
Overloading and generic constraints (me)
Constraints are not part of the signature (Eric Lippert)
Evil code - overload resolution workaround (me - really nasty stuff, but fun)
EDIT: Note that using an "enumerableOrQueryable" is always going to convert your lambda expression to a delegate, not an expression tree. So if you wanted it to perform the logic differently for a database, you'd need a change anyway.
EDIT: Your idea also wouldn't work because you wouldn't get the same result type out anyway - if you call Where on a List<string>, the returned value isn't a List<string>.
What you can do is this, if you can introduce a new interface to be implemented by both ClassA and ClassB:
public static IQueryable<T> IsActive<T>(this IQueryable<T> source, bool isActive)
where T : ICanBeActive
{
// Lambda converted to an expression tree
return source.Where(x => x.IsActive == isActive);
}
public static IEnumerable<T> IsActive<T>(this IEnumerable<T> source,
bool isActive) where T : ICanBeActive
{
// Lambda converted to a delegate
return source.Where(x => x.IsActive == isActive);
}
The compiler cannot resolve ambiguity from the generic constraints. For your case, can't you just do something like this ?
public static IEnumerable<ClassA> IsActive(this IEnumerable<ClassA> enumerableOrQueryable, bool isActive)
{
return enumerableOrQueryable.Where(x => x.IsActive == isActive);
}
You can try something like this:
public interface IActivatable
{
bool IsActive { get; set; }
}
public class ClassA : IActivatable
{
public bool IsActive{ get; set;}
}
public class ClassB : IActivatable
{
public bool IsActive { get; set;}
}
public static class Ext
{
public static IEnumerable<T> IsActive<T>(this IEnumerable<T> collection, bool isActive) where T : IActivatable
{
return collection.Where(x => x.IsActive == isActive);
}
}

Categories