I have a class called IDCollection which is not actually a List<>, Dictionary<,>, or similar IEnumerable-based type. Though it does have an indexer, it's based on a private Dictionary<string, ID> called innerList, so objects of the class themselves are not lists, nor does it hold key value pairs or a collection of items through its own this accessor.
Is it possible to make an IDCollection object queryable in a LINQ expression? If so, how?
For example, suppose the object is called testIdColl. In that case...
from KeyValuePair<string, ID> k in testIDColl
select k;
etc.
And is the IQueryable interface involved at all?
This is all you would need to do to your class:
public class IDCollection : IEnumerable<KeyValuePair<string, ID>>
{
private IDictionary<string, ID> List = new Dictionary<string, ID>();
public IEnumerator<KeyValuePair<string, ID>> GetEnumerator()
{
return List.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Then you could run this code:
var testIDColl = new IDCollection();
var query =
from KeyValuePair<string, ID> k in testIDColl
select k;
If you want you could make the entire IEnumerable<...> interface private like so:
public class IDCollection : IEnumerable<KeyValuePair<string, ID>>
{
private IDictionary<string, ID> List = new Dictionary<string, ID>();
IEnumerator<KeyValuePair<string, ID>> IEnumerable<KeyValuePair<string, ID>>.GetEnumerator()
{
return List.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return List.GetEnumerator();
}
}
Now nothing is directly exposed.
I created an implementation of the three instance methods from Jakub's answer:
public class IDCollection
{
private IDictionary<string, ID> List = new Dictionary<string, ID>() { { "x", new ID() }, } ;
public IEnumerable<KeyValuePair<string, ID>> Where(Func<KeyValuePair<string, ID>, bool> selector)
{
return List.Where(selector);
}
public IEnumerable<TResult> Select<TResult>(Func<KeyValuePair<string, ID>, TResult> selector)
{
return List.Select(selector);
}
}
The Cast method was not needed to perform basic queries.
I would suggest adding an explicit AsEnumerable() method instead to expose the full range of LINQ operators.
This would be the simplest and most robust way of doing queries:
public class IDCollection
{
private IDictionary<string, ID> List = new Dictionary<string, ID>() { { "x", new ID() }, } ;
public IEnumerable<KeyValuePair<string, ID>> AsEnumerable()
{
return List.Select(x => x);
}
}
The queries would have to look like:
var query =
from k in testIDColl.AsEnumerable()
where k.Key == "x"
select k;
The easiest solution is to implement IEnumerable<T>. It's only one method, which you can usually delegate to inner collection's GetEnumerator() or implement easily with yield return.
The name of your type (IDCollection) suggests that it should implement IEnumerable<T>, probably some other collection interface (e.g. ICollection<T>, IReadonlyCollection<T>).
If for some reason you don't want to use IEnumerable<T>, you can still make it work. First you need to understand how the compiler processes query expressions.
A LINQ query expression is first translated by the compiler to a series of method calls. For example the query expression
from KeyValuePair<string, int> item in collection
where item.Key == "abc"
select item.Value;
Is translated to
testIDColl
.Cast<KeyValuePair<string, int>>()
.Where(item => item.Key == "abc")
.Select(item => item.Value);
All you need to do to use a type as a source in a query expression is to make the above code compile. It means you will need Cast, Where, Select (and others too, like GroupBy, OrderBy) methods either as instance methods or extension methods.
For example the following class and extension methods will make the above query expression compile (although the methods don't do anything at all):
class IDCollection
{
}
static class IDCollectionExtensions
{
public static IDCollection Cast<TResult>(this IDCollection source)
{
return source;
}
public static IDCollection Where(this IDCollection source, Func<KeyValuePair<string, int>, bool> selector)
{
return source;
}
public static IDCollection Select<TResult>(this IDCollection source, Func<KeyValuePair<string, int>, TResult> selector)
{
return source;
}
}
Instance methods will work too:
class IDCollection
{
public IDCollection Cast<TResult>()
{
return this;
}
public IDCollection Where(Func<KeyValuePair<string, int>, bool> selector)
{
return this;
}
public IDCollection Select<TResult>(Func<KeyValuePair<string, int>, TResult> selector)
{
return this;
}
}
Related
public class Flea : Animals {...}
var fleas = new Dictionary<int, Flea>();
public IReadOnlyDictionary<string, Animal> Animals => fleas.ToDictionary(pair => pair.Key, pair => (Animal)pair.Value);
Q Is there a more efficient way to obtain Animals from fleas?
.NET supports covariance in interfaces, delegates, generic types and arrays. The interface or type has to specify it's covariant though with the out keyword.
You can write
IEnumerable<Animal> animals=new List<Flea>();
or
var dict=new Dictionary<int,Flea>{
[1]=new Flea()
};
IEnumerable<Animal> animals=dict.Values;
This works because Dictionary.Values returns an IEnumerable<Flea> and IEnumerable is covariant - its definition is IEnumerable<out T>.
KeyValuePair though isn't covariant which means that the classes that use it like IDictionary<TKey,TValue> and IReadOnlyDictionary<TKey,TValue> aren't either. This was intentional.
Since you only need to read from that dictionary, you can create an accessor method using a delegate or, in C# 7 and later, a local function. You can pass that function to methods that expect a Func<TKey,TValue> and use it to read values from the dictionary.
If you have a method that needs key-based access, let's say :
void Process(Func<int,Animal> reader)
{
var value=reader(1);
}
In C# 7 you can write :
var dict =...
Animal get(int key)=>dict[key];
Process(get);
This cheats a bit, by using variable capture to access the dictionary.
Before C# 7 you'd use a delegate :
Func<int,Animal> get= key=>dict[key];
Process(get);
This may seem strange, but that's how LINQ itself works, by using predicates and delegates instead of interfaces and wrappers.
The .NET framework does not contain a dictionary wrapper that supports upcasting, but implementing one is trivial:
public class ReadOnlyDictionaryUpcast<TKey, TValueDerived, TValueBase>
: IReadOnlyDictionary<TKey, TValueBase> where TValueDerived : TValueBase
{
private readonly Dictionary<TKey, TValueDerived> _dictionary;
public ReadOnlyDictionaryUpcast(Dictionary<TKey, TValueDerived> dictionary)
{
_dictionary = dictionary;
}
public int Count => _dictionary.Count;
public TValueBase this[TKey key] => _dictionary[key];
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
public bool TryGetValue(TKey key, out TValueBase value)
{
bool result = _dictionary.TryGetValue(key, out TValueDerived valueDerived);
value = valueDerived;
return result;
}
public IEnumerator<KeyValuePair<TKey, TValueBase>> GetEnumerator() => _dictionary
.Select(e => new KeyValuePair<TKey, TValueBase>(e.Key, e.Value))
.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<TKey> Keys => _dictionary.Keys;
public IEnumerable<TValueBase> Values =>
(IEnumerable<TValueBase>)(IEnumerable<TValueDerived>)_dictionary.Values;
}
Usage example:
var animals = new ReadOnlyDictionaryUpcast<string, Flea, Animal>(fleas);
I'm using IDocumentClient to retrieve and update items in a DocumentDB collection.
The code for retrieving a list of documents that match a condition looks like this:
public static async Task<FeedResponse<T>> GetDocuments<T>(
this IDocumentClient client,
string collection,
Expression<Func<T, bool>> filter)
{
IDocumentQuery<T> query = client.CreateDocumentQuery<T>(GetCollectionUri(collection)).Where(filter)
.AsDocumentQuery();
return await query.ExecuteNextAsync<T>().ConfigureAwait(false);
}
In order to unit test the code above against a list of mock items, I've created a mock class:
public class MockIOrderedQueryable<T> : List<T>, IOrderedQueryable<T>, IDocumentQuery<T>
{
public Expression Expression
{
get
{
var content = this.ToList();
return content.AsQueryable().Expression;
}
}
public IQueryProvider Provider => new MyProvider<T>(this.ToList());
public Task<FeedResponse<TResult>> ExecuteNextAsync<TResult>(CancellationToken token = new CancellationToken())
{
var tmp = new FeedResponse<TResult>((IEnumerable<TResult>)this);
return Task.FromResult(tmp);
}
}
The Where filter is an extension method on IQueryable<T>, so I needed an implementation that looks like this:
public class MyQueryable<T> : IQueryable<T>, IDocumentQuery<T>
{
private readonly List<T> _list;
public MyQueryable(List<T> list)
{
_list = list;
}
public Task<FeedResponse<TResult>> ExecuteNextAsync<TResult>(CancellationToken token = new CancellationToken())
{
var tmp = new FeedResponse<TResult>(_list as List<TResult>);
return Task.FromResult(tmp);
}
}
And also an implementation of IQueryProvider that returns the IQueryable instance to my original mock class via CreateQuery:
public class MyProvider<T> : IQueryProvider
{
private readonly List<T> _list;
public MyProvider(List<T> list)
{
_list = list;
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new MyQueryable<TElement>(_list as List<TElement>);
}
}
For brevity, I omitted the code for the methods that throw NotImplementedException and also for the fields that are not used.
This all looks fine, but there's one thing I did not manage to do: applying the real filtering passed as Expression in CreateQuery on the _list member of MyProvider. I tried calling Invoke and retrieving the arguments, but it did not work. The expression returned in MockIOrderedQueryable is probably not the good one (.AsQueryable on the list). I'd like to get to a lambda Expression<Func<T, bool>> and call it on the list.
Any help appreciated.
I want to write a method which return all key value pairs containing in a IDictionary as Map.EntrySet() does in java.
I tried as:
For example we define IDictionary as:
private IDictionary<T, MutableInt> _map = new Dictionary<T, MutableInt>();
The method as:
public KeyValuePair<T, MutableInt> KeyValuePairSet()
{
return KeyValuePair<T, MutableInt>(_map.Keys, _map.Values);
}
while returning statement, the error raised is:
KeyValuePair<T, MutableInt> is a type but used like a variable
How can this method be implemented?
Actually it is fairly easily, because IDictionary<TKey, TValue> implmentents the interface IEnumerable<KeyValuePair<TKey, TValue>> all you need to do is declare your HashSet and pass the dictionary in because HashSet<T> has a constructor that takes in a IEnumerable<T> as its parameter.
public ISet<KeyValuePair<T, MutableInt>> KeyValuePairSet()
{
return new HashSet<KeyValuePair<T, MutableInt>>(_map);
}
Given:
private IDictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
If you want to return IEnumerable of KeyValuePairs:
IEnumerable<KeyValuePair<T, MutableInt>> get_pairs()
{
return map;
}
If you want to return KeyValuePair of keys and values of map:
KeyValuePair<IEnumerable<T>, IEnumerable<MutableInt>> get_pair()
{
return new KeyValuePair<IEnumerable<T>, IEnumerable<MutableInt>>(map.Keys, map.Values);
}
If you want to return HashSet of KeyValuePairs:
ISet<KeyValuePair<T, MutableInt>> get_pairs()
{
return new HashSet<KeyValuePair<T, MutableInt>>(map);
}
I need to create an extension method that will filter collection List<TSource> according to a list of validation rules List<<IRule>, bool>.
But I get an error VisitSubQueryExpression method is not implemented and I don't see/can not find what is the problem cause.
This is my extension method:
public static List<TSource> ValidItems<TSource>(this IQueryable<TSource> source,
List<IValidationRule<TSource>> validationRules)
{
return source.Where(testableItem =>
validationRules.All(rule => rule.RulePassed(testableItem))).ToList();
}
IRule interface:
public interface IValidationRule<T> //with implementation class ValidationRule<T>
{
Func<T, bool> RulePassed { get; set; }
//... +other code
}
Sample of extension method call
//initialization of List<SampleType> listToValidate = ...
var validItems = listToValidate.ValidItems(
new List<IValidationRule<SampleType>() {
new ValidationType<SampleType> {
RulePassed = (s) => string.IsNullOrWhiteSpace(SampleType.Name),
//...initalize other ValidationType parameters
}
});
this sample should filter listToValidate list and remove all SampleType instances, with Name property that is Null or Whitespace
What is wrong with my extension method? What does this "VisitSubQueryExpression method is not implemented" error mean?
if I change it to be an extension method for List<TSource> not IQueryable<TSource> - it works! Why?
replacing this IQueryable<TSource> with this List<TSource>, it works, why? Where method should work on IQueryable<T> (inherits from IEnumerable<T>), shouldn't it?
public static List<TSource> ValidItems<TSource>(this List<TSource> source,
List<IValidationRule<TSource>> validationRules)
{
return source.Where(testableItem =>
validationRules.All(rule => rule.RulePassed(testableItem))).ToList();
}
Your rule.RulePassed cannot be translated by your IQueryable provider.
public static List<TSource> ValidItems<TSource>(this IQueryable<TSource> source,
List<IValidationRule<TSource>> validationRules)
{
var result = new List<TSource>();
foreach (var testableItem in source)
{
if (validationRules.All(rule => rule.RulePassed(testableItem))
{
result.Add(testableItem);
}
}
return result;
}
IQueryable<T> implements IEnumerable<T> but not vice versa. And List<T> doesn't implement IQueryable<T>.
This is the list of interfaces exposed by List:
Since both IQueryable and IList inherit from IEnumerable<T> you could use that and call .AsQueryable on it to convert both cases.
List<T> does not implement IQueryable<T>, so you can't call an extension method on it defined on IQueryable<T>.
I am very curious to know how to modify an existing LINQ function to add Func<T> TResult to the function signature, i.e. allow it to use a selector as in (o => o.CustomField).
For example, in C#, I can use .IsDistinct() to check if a list of integers are distinct. I can also use .IsDistinctBy(o => o.SomeField) to check if the integers in field o.SomeField are distinct. I believe that, behind the scenes, .IsDistinctBy(...) has something like the function signature Func<T> TResult appended to it?
My question is this: what is the technique for taking an existing LINQ extension function, and converting it so it can have a parameter (o => o.SomeField)?
Here is an example.
This extension function checks to see if a list is increasing monotonically (i.e. values are never decreasing, as in 1,1,2,3,4,5,5):
main()
{
var MyList = new List<int>() {1,1,2,3,4,5,5};
DebugAssert(MyList.MyIsIncreasingMonotonically() == true);
}
public static bool MyIsIncreasingMonotonically<T>(this List<T> list) where T : IComparable
{
return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) <= 0).All(b => b);
}
If I want to add a "By", I add a parameter Func<T> TResult. But how do I modify the body of the function to make it select by (o => o.SomeField)?
main()
{
DebugAssert(MyList.MyIsIncreasingMonotonicallyBy(o => o.CustomField) == true);
}
public static bool MyIsIncreasingMonotonicallyBy<T>(this List<T> list, Func<T> TResult) where T : IComparable
{
// Question: How do I modify this function to make it
// select by o => o.CustomField?
return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) <= 0).All(b => b);
}
Consider an implementation like the following, which enumerates the given IEnumerable<T> only once. Enumerating can have side-effects, and callers typically expect a single pass-through if that's possible.
public static bool IsIncreasingMonotonically<T>(
this IEnumerable<T> _this)
where T : IComparable<T>
{
using (var e = _this.GetEnumerator())
{
if (!e.MoveNext())
return true;
T prev = e.Current;
while (e.MoveNext())
{
if (prev.CompareTo(e.Current) > 0)
return false;
prev = e.Current;
}
return true;
}
}
Your enumerable.IsIncreasingMonotonicallyBy(x => x.MyProperty) overload that you describe can now be written as follows.
public static bool IsIncreasingMonotonicallyBy<T, TKey>(
this IEnumerable<T> _this,
Func<T, TKey> keySelector)
where TKey : IComparable<TKey>
{
return _this.Select(keySelector).IsIncreasingMonotonically();
}
Just apply the Func to a and b:
public static bool MyIsIncreasingMonotonicallyBy<T, TResult>(this IEnumerable<T> list, Func<T, TResult> selector)
where TResult : IComparable<TResult>
{
return list.Zip(list.Skip(1), (a, b) => selector(a).CompareTo(selector(b)) <= 0).All(b => b);
}
One above is close to right but there are issues:
Your list has possible multiple enumeration of IEnumeration
public static bool MyIsIncreasingMonotonicallyBy<T, TResult>(
this IEnumerable<T> list, Func<T, TResult> selector)
where TResult : IComparable<TResult>
{
var enumerable = list as IList<T> ?? list.ToList();
return enumerable.Zip(
enumerable.Skip(1),
(a, b) => selector(a).CompareTo(selector(b)) <= 0
).All(b => b);
}
P.S. I believe you need to remove the "this" because Extension method can only be declared in non-generic, non-nested static class.
In response to Frédéric Hamidi:
Consider the following:
IEnumerable<string> names = GetNames();
foreach (var name in names) Console.WriteLine("Found " + name);
var allNames = new StringBuilder();
foreach (var name in names) allNames.Append(name + " ");
Assuming that GetNames() returns an IEnumerable, we are, effectively, doing extra work by enumerating this collection twice in the two foreach statements. If GetNames() results in a database query, you end up doing that query twice, while both times getting the same data.
This kind of problem can be easily fixed – simply force the enumeration at the point of variable initialization by converting the sequence to a list(or you could do array). Both array and list types implement the IEnumerable interface.