Using LINQ in shared collections

Please consider the following snippet from the implementation of the interpreter template:

public override object Execute(Interpreter interpreter, object ctx) { var list = ctx as IEnumerable<string>; return (list != null) ? list.FirstOrDefault() : null; } 

How about if I want to use the same function for integers?

 public override object Execute(Interpreter interpreter, object ctx) { var list = ctx as IEnumerable<string>; if (list != null) return list.FirstOrDefault(); var list = ctx as IEnumerable<int>; return (list != null) ? list.FirstOrDefault() : null; } 

What I wanted was something like:

 public override object Execute(Interpreter interpreter, object ctx) { var list = ctx as IEnumerable; return (list != null) ? list.FirstOrDefault() : null; } 

But Linq doesn't act on IEnumerables. Instead, to get to this solution, I would have to write something like:

 public override object Execute(Interpreter interpreter, object ctx) { var list = ctx as IEnumerable; if (list != null) foreach(var i in list) { yield return i; return; } return null; } 

Or use the general method:

 public override T Execute<T>(Interpreter interpreter, object ctx) { var list = ctx as IEnumerable<T>; return (list != null) ? list.FirstOrDefault() : null; } 

What violates the interpreter pattern (how it was implemented in this system). Covariance will also fail (at least in C # 3), although this will work, this would be the exact behavior I wanted:

 public override object Execute(Interpreter interpreter, object ctx) { var list = ctx as IEnumerable<object>; return (list != null) ? list.FirstOrDefault() : null; } 

So my question is: what's the best way to achieve intended behavior?


Addendum: digEmAll offers something like the following code:

 var list = ctx as IEnumerable; return (list != null) ? list.Cast<object>().FirstOrDefault() : null; 

This is a good answer for things like FirstOrDefault (). The problem is related to things like Reverse:

 var list = ctx as IEnumerable; return (list != null) ? list.Cast<object>().Reverse() : null; 

I could feed this method a List<int> , but I will return to List<object> . I know that there is no way to circumvent covariance. So I think digEmAll code is the best answer.


Thanks: -)

+4
source share
3 answers

Something like this might suit your needs?

 public override object Execute(Interpreter interpreter, object ctx) { var nonGenericlist = ctx as IEnumerable; if (nonGenericlist == null) return null; var list = nonGenericlist.Cast<object>(); return (list != null) ? list.FirstOrDefault() : null; } 
+3
source

It seems that you want to have security types and LINQ support, while not defining the involved types that you cannot do in C #.

One option is Execute overloads, and not accepting object ctx can take the corresponding IEnumerable<T> as a parameter?

For example, you may have several overloads:

 public override object Execute(Interpreter interpreter, IEnumerable<int> ctx) public override object Execute(Interpreter interpreter, IEnumerable<string> ctx) public override object Execute(Interpreter interpreter, IEnumerable<...> ctx) 

Alternatively, you can reuse LINQ methods that you want to work with simple IEnumerable . Doing this for FirstOrDefault is relatively easy:

 public static object FirstOrDefault( this IEnumerable sequence ) { if( sequence == null ) return null; using( var iter = sequence.GetEnumerator() ) { if( iter.MoveNext() ) return iter.Current; return null; } } 

Reimplementing all LINQs in IEnumerable will not be fun ... or in some cases easy. It would be best to create an adapter that allows you to handle IEnumerable as an IEnumerable<object> - then you can use it regardless of whether you are dealing with value type sequences or reference types:

 public static IEnumerable<object> AsObjectSequence( this IEnumerable sequence ) { foreach( object x in sequence ) yield return x; } 

EDIT: Turns out this is basically equivalent to using:

 sequence.Cast<object>() 

therefore, yoy may want to use this as it is more concise and directly embedded in LINQ.

+2
source

Don't worry about breaking design patterns if the code does what you want. Design patterns are tools that solve specific problems. If you cannot put your solution in a template, the template is not the right solution. If every tool in your tool is some kind of hammer, every decision comes down to a β€œhammer blow." Sometimes the right solution is to use a scredriver or even invent a new tool.

0
source

Source: https://habr.com/ru/post/1309325/


All Articles