In the code below, note that Bar derives from Foo.
class Program
{
public class Foo
{
public string data { get; set; }
}
public class Bar : Foo
{
}
static void Main(string[] args)
{
var bars = new List<Bar>();
bars.Add(new Bar() { data = "hello" });
bars.Add(new Bar() { data = "world" });
var resultsA = GetFoos(bars, (b => b.data.StartsWith("h")));
var resultsB = GetBars(bars, (b => b.data.StartsWith("h")));
}
static List<Foo> GetFoos(List<Foo> fooList, Func<Foo, bool> criteria)
{
return fooList.Where(criteria).ToList();
}
static List<Bar> GetBars(List<Bar> barList, Func<Bar, bool> criteria)
{
return barList.Where(criteria).ToList();
}
}
The GetFoos method call results in this compiler error message:
Argument 1: cannot convert from 'System.Collections.Generic.List<Program.Bar>' to 'System.Collections.Generic.List<Program.Foo>'
However, when that line is commented out, the call to GetBars() executes correctly.
Is what I'm trying to accomplish here, a query against a common ancestor class, possible with linq?
Only interfaces can be covariant. Since you are trying to assign a List<Derived> to a List<Base>, you need to use a covariant interface instead. IEnumerable is already covariant, so just change your code to:
static List<Foo> GetFoos(IEnumerable<Foo> fooList, Func<Foo, bool> criteria)
{
return fooList.Where(criteria).ToList();
}
static List<Bar> GetBars(IEnumerable<Bar> barList, Func<Bar, bool> criteria)
{
return barList.Where(criteria).ToList();
}
Proof on IdeOne
Update the List to IEnumerable:
static IEnumerable<Foo> GetFoos(IEnumerable<Foo> fooList, Func<Foo, bool> criteria)
{
return fooList.Where(criteria).ToList();
}
static IEnumerable<Bar> GetBars(IEnumerable<Bar> barList, Func<Bar, bool> criteria)
{
return barList.Where(criteria).ToList();
}
This is because IEnumerable<Bar> is a subtype of IEnumerable<Foo>. The subtyping is preserved because IEnumerable<T> is covariant on T.
Neither IList<Boo> nor IList<Foo> is a subtype of the other, because IList<T> is invariant on T.
Related
var someList = otherList.ReplaceAll(foo, bar);
if (someCondition)
{
someList = someList.ReplaceAll(someOtherFoo, someOtherBar);
}
In my code, I am having the above code snippet, I find the if statement very annoying and would like to do something like this instead:
var someList = otherList
.ReplaceAll(foo, bar)
.Given(someCondition)
.ReplaceAll(someOtherFoo, someOtherBar);
such that ReplaceAll(someOtherFoo, someOtherBar) is only executed when someCondition is true.
Is that possible?
While you can indeed create an extension as suggested by others, I wouldn't do that in actual production code because it's defeats the purpose of Linq.
Linq is functional and good for processing sequences or streams. Each Linq chaining operator processes incoming data and transforms it to another data. Given extension you are looking for is procedural and doesn't do anything with the sequence.
Given also doesn't support lazy evaluation which is one of the features of Linq.
By introducing such extension you just making the code harder to read for the next person working on this code.
By contrast, good old if can be easily understood by everyone.
If you want to save couple of lines you can use ternary operator:
var someList = otherList.ReplaceAll(foo, bar);
someList = someCondition ? someList.ReplaceAll(someOtherFoo, someOtherBar) : someList;
Why don't you create an extension?
public static List<T> ExecuteIf<T>(
this List<T> list,
Func<bool> condition,
Func<List<T>, List<T>> action)
{
return condition() ? action(list) : list;
}
var someList = otherList
.ReplaceAll(foo, bar)
.ExecuteIf(() => someCondition, (l) => l.ReplaceAll(someOtherFoo, someOtherBar));
what you are describing is called a fluent interface
the linq functions are extension functions with a signature like
IEnumerable<T> someFunction<T>(this IEnumerable<T>, ...)
as you see it's an ordinary function that returns something ...
fluent interfaces make use of this by returning something that is implementing an interface for enumeration in this case, but also using the return type to change the set of functions you can call on the result ...
here is an example program...
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace SoFluentExample
{
class Program
{
static void Main(string[] args)
{
var en = Enumerable.Range(0, 10).Concat(Enumerable.Range(0, 10));
var result = en
.ReplaceAll(1, 100)
.Given(true)
.ReplaceAll(2, 200)
.Given(false)
.ReplaceAll(3,300)
.ToArray();
}
}
public class MyFluentEnumerableWithCondition<T> : IEnumerable<T>
{
public IEnumerable<T> en { get; private set; }
public bool condition { get; private set; }
public MyFluentEnumerableWithCondition(IEnumerable<T> en, bool condition)
{
this.en = en;
this.condition = condition;
}
public IEnumerator<T> GetEnumerator()
{
return en.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return en.GetEnumerator();
}
}
public class MyFluentReplacerEnumerable<T> : IEnumerable<T>
{
private IEnumerable<T> en;
private T foo;
private T bar;
public MyFluentReplacerEnumerable(IEnumerable<T> en, T foo, T bar)
{
this.en = en;
this.foo = foo;
this.bar = bar;
}
public IEnumerator<T> GetEnumerator()
{
return new MyEnumerator(en.GetEnumerator(), foo, bar);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class MyEnumerator : IEnumerator<T>
{
private IEnumerator<T> en;
private T foo;
private T bar;
public MyEnumerator(IEnumerator<T> enumerator,T foo, T bar)
{
this.en = enumerator;
this.foo = foo;
this.bar = bar;
}
public T Current => replace(en.Current,foo,bar);
private T replace(T current, T foo, T bar)
{
return current.Equals(foo) ? bar : current;
}
object IEnumerator.Current => Current;
public bool MoveNext()
{
return en.MoveNext();
}
public void Reset()
{
en.Reset();
}
#region IDisposable Support
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
en.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
#endregion
}
}
public static class MyExtension
{
public static IEnumerable<T> ReplaceAll<T>(this IEnumerable<T> en,T foo, T bar)
{
return new MyFluentReplacerEnumerable<T>(en, foo, bar);
}
public static MyFluentEnumerableWithCondition<T> ReplaceAll<T>(this MyFluentEnumerableWithCondition<T> en, T foo, T bar)
{
if (!en.condition)
return en;
return new MyFluentEnumerableWithCondition<T>(en.en.ReplaceAll(foo,bar),true);
}
public static MyFluentEnumerableWithCondition<T> Given<T>(this IEnumerable<T> en, bool condition)
{
return new MyFluentEnumerableWithCondition<T>(en, condition);
}
}
}
ReplaceAll is defined for IEnumerable<T> and MyFluentEnumerableWithCondition<T>
the type decides which implementation is called, and even though MyFluentEnumerableWithCondition<T> is implementing IEnumerable<T>, the more specific signature is used
To use fluent method chaining with such a conditional operation, you could create a ReplaceAllIf extension method:
public static class Extensions
{
public static List<T> ReplaceAllIf<T>(this List<T> list, bool condition, T valueToFind, T replacement)
{
return condition ? list.ReplaceAll(valueToFind, replacement) : list;
}
public static List<T> ReplaceAll<T>(this List<T> list, T valueToFind, T replacement)
{
return list.Select(x => x.Equals(valueToFind) ? replacement : x).ToList();
}
}
And then use it like this:
var list = new List<string>{"a", "b", "c", "d", "a", "b", "c", "d"};
var result = list
.ReplaceAll("a", "XXXX")
.ReplaceAllIf(true, "c", "YYYY")
.ReplaceAllIf(false, "d", "ZZZZ");
Working demo -> https://dotnetfiddle.net/gknS4z
I am quite new to c sharp.In order to grasp the idea about generic,callback and extension methods i've comp up with the following example.The extension method i wrote will operate on a IEnumerable type and will accept a callback and a integer parameter "year".It will filter out the IEnumerable and return only the item which will pass the test.But while executing the program i've encountered some error :
The type argument for the extension method can not be inferred from
the usage
and for the "return item " inside extension method i am getting error
: can not implicitly convert type T to
System.Collections.Generic.IEnumerable .An explicit conversion
exists.
class Program
{
static void Main(string[] args)
{
List<Students> students = new List<Students>();
students.Add(new Students("zami", 1991));
students.Add(new Students("rahat", 2012));
students.FilterYear((year) =>
{
List<Students> newList = new List<Students>();
foreach (var s in students)
{
if (s.byear >= year)
{
newList.Add(s);
}
}
return newList;
}, 1919);
}
}
public static class LinqExtend
{
public static IEnumerable<T> FilterYear<T>(this IEnumerable<T> source, Func<int, T> callback, int year)
{
var item = callback(year);
return item;
}
}
public class Students
{
public string name;
public int byear;
public Students(string name, int byear)
{
this.name = name;
this.byear = byear;
}
}
Based on how it was used in the OP the assumption is that the callback was suppose to return an enumeration.
The extension method also has an issue in that it is returning a single T and not IEnumerable<T> given the function.
Update the extension method's callback Func<int, IEnumerable<T>> callback
public static class LinqExtend {
public static IEnumerable<T> FilterYear<T>(this IEnumerable<T> source, Func<int, IEnumerable<T>> callback, int year) {
var items = callback(year);
return items;
}
}
Given the example in the OP it also looks like you are re-inventing already existing functionality.
You can use LINQ Where to attain the same result.
var year = 1919;
var items = students.Where(s => s.byear >= year).ToList();
essentially, exactly as in this question, but in c#.
I want to have something like this:
public IList<double> DoSomething(IList<string> strings) {
//something
}
But i'd rather have it typed such that the return value is known ahead of time so that i don't have to cast or anything outside the function. How do i do this?
Is there a generic way,
public ListType<double> DoSomething<ListType>(ListType<string> strings) where ListType : ???{
to set this up?
C# does not allow exactly what you want, but the closest thing would be:
public TList2 DoSomething<TList1, TList2>(TList1 strings)
where TList1 : IEnumerable<string>
where TList2 : ICollection<decimal>, new()
{
var result = new TList2();
foreach (var s in strings)
{
result.Add(decimal.Parse(s));
}
return result;
}
and an example:
var input = new HashSet<string>(new[] { "1", "2", "3"});
List<decimal> output = DoSomething<HashSet<string>, List<decimal>>(input);
You can use Linq to do this.
For instance if you just want to parse to double you would do:
List<double> result = strings.Select(double.Parse).ToList()
And you can send in any other method instead of double.Parse:
List<double> result = strings.Select(DoSomethingWithOneItem).ToList()
double DoSomethingWithOneItem(string item) {
//your conversion logic
}
Unfortunately there is no relation between for instance IList<TInput> and IList<TOutput> that can be used to help here, so you will need to specify both the input and output list type, which becomes a bit cumbersome in the general form:
IList<string> strings = new List<string> {"1.1", "2.2", "3.3"};
IList<decimal> result = strings.ConvertToSameListType((Func<string, decimal>)decimal.Parse, () => new List<decimal>());
public static class EnumerableExtensioncGeneralVersion
{
public static TOutputList ConvertToSameListType<TInputList, TOutputList, TInput, TOutput>(this TInputList source, Func<TInput, TOutput> itemConversion, Func<TOutputList> outputListConstructor)
where TInputList : IEnumerable<TInput>
where TOutputList : ICollection<TOutput>
{
TOutputList result = outputListConstructor();
foreach (TOutput convertedItem in source.Select(itemConversion))
{
result.Add(convertedItem);
}
return result;
}
}
Though you can make it much nicer to use your conversions if you just specify one extension method for each of your favourite collection types that you want to support:
//Seting up inputs
IList<string> strings = new List<string> {"1.1", "2.2", "3.3"};
IEnumerable<string> enumerableStrings = strings.Select(x => x);
ObservableCollection<string> observableStrings = new ObservableCollection<string>(strings);
//Converting
IList<decimal> resultList = strings.Convert(decimal.Parse);
IEnumerable<decimal> resultEnumerable = enumerableStrings.Convert(decimal.Parse);
ObservableCollection<decimal> observableResult = observableStrings.Convert(decimal.Parse);
public static class EnumerableExtensions
{
public static IList<TOutput> Convert<TInput, TOutput>(this IList<TInput> source, Func<TInput, TOutput> itemConversion)
{
return source.Select(itemConversion).ToList();
}
public static IEnumerable<TOutput> Convert<TInput, TOutput>(this IEnumerable<TInput> source, Func<TInput, TOutput> itemConversion)
{
return source.Select(itemConversion);
}
public static ObservableCollection<TOutput> Convert<TInput, TOutput>(this ObservableCollection<TInput> source, Func<TInput, TOutput> itemConversion)
{
return new ObservableCollection<TOutput>(source.Select(itemConversion));
}
}
I would like to write Generic Method that would map List to new list, similar to JS's map method. I would then use this method like this:
var words= new List<string>() { "Kočnica", "druga beseda", "tretja", "izbirni", "vodno bitje" };
List<object> wordsMapped = words.Map(el => new { cela = el, končnica = el.Končnica(5) });
I know there's Select method which does the same thing but I need to write my own method. Right now I have this:
public static IEnumerable<object> SelectMy<T>(this IEnumerable<T> seznam, Predicate<T> predicate)
{
List<object> ret = new List<object>();
foreach (var el in seznam)
ret.Add(predicate(el));
return ret;
}
I also know I could use yield return but again I mustn't. I think the problem is with undeclared types and compiler can't figure out how it should map objects but I don't know how to fix that. All examples and tutorials I found map object of same types.
Linq's Select is the equivalent of the map() function in other functional languages. The mapping function would typically not be called Predicate, IMO - predicate would be a filter which could reduce the collection.
You can certainly wrap an extension method which would apply a projection to map input to output (either of which could be be anonymous types):
public static IEnumerable<TO> Map<TI, TO>(this IEnumerable<TI> seznam,
Func<TI, TO> mapper)
{
foreach (var item in seznam)
yield return mapper(item);
}
Which is equivalent to
public static IEnumerable<TO> Map<TI, TO>(this IEnumerable<TI> seznam,
Func<TI, TO> mapper)
{
return seznam.Select(mapper);
}
And if you don't want a strong return type, you can leave the output type as object
public static IEnumerable<object> Map<TI>(this IEnumerable<TI> seznam, Func<TI, object> mapper)
{
// Same implementation as above
And called like so:
var words = new List<string>() { "Kočnica", "druga beseda", "tretja", "izbirni", "vodno bitje" };
var wordsMapped = words.Map(el => new { cela = el, končnica = el.Končnica(5) });
Edit
If you enjoy the runtime thrills of dynamic languages, you could also use dynamic in place of object.
But using dynamic like this so this precludes the using the sugar of extension methods like Končnica - Končnica would either need to be a method on all of the types utilized, or be invoked explicitly, e.g.
static class MyExtensions
{
public static int Končnica(this int i, int someInt)
{
return i;
}
public static Foo Končnica(this Foo f, int someInt)
{
return f;
}
public static string Končnica(this string s, int someInt)
{
return s;
}
}
And then, provided all items in your input implemented Končnica you could invoke:
var things = new List<object>
{
"Kočnica", "druga beseda",
53,
new Foo()
};
var mappedThings = things.Map(el => new
{
cela = el,
končnica = MyExtensions.Končnica(el, 5)
// Or el.Končnica(5) IFF it is a method on all types, else run time errors ...
})
.ToList();
You can fix your code to work correctly like this:
public static IEnumerable<TResult> SelectMy<T, TResult>(this IEnumerable<T> seznam,
Func<T, TResult> mapping)
{
var ret = new List<TResult>();
foreach (var el in seznam)
{
ret.Add(mapping(el));
}
return ret;
}
Note that this is inefficient and problematic compared to typical Linq extensions, because it enumerates the entire input at once. If the input is an infinite series, you are in for a bad time.
It is possible to remedy this problem without the use of yield, but it would be somewhat lengthy. I think it would be ideal if you could tell us all why you are trying to do this task with two hands tied behind your back.
As a bonus, here is how you could implement this with the lazy evaluation benefits of yield without actually using yield. This should make it abundantly clear just how valuable yield is:
internal class SelectEnumerable<TIn, TResult> : IEnumerable<TResult>
{
private IEnumerable<TIn> BaseCollection { get; set; }
private Func<TIn, TResult> Mapping { get; set; }
internal SelectEnumerable(IEnumerable<TIn> baseCollection,
Func<TIn, TResult> mapping)
{
BaseCollection = baseCollection;
Mapping = mapping;
}
public IEnumerator<TResult> GetEnumerator()
{
return new SelectEnumerator<TIn, TResult>(BaseCollection.GetEnumerator(),
Mapping);
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
internal class SelectEnumerator<TIn, TResult> : IEnumerator<TResult>
{
private IEnumerator<TIn> Enumerator { get; set; }
private Func<TIn, TResult> Mapping { get; set; }
internal SelectEnumerator(IEnumerator<TIn> enumerator,
Func<TIn, TResult> mapping)
{
Enumerator = enumerator;
Mapping = mapping;
}
public void Dispose() { Enumerator.Dispose(); }
public bool MoveNext() { return Enumerator.MoveNext(); }
public void Reset() { Enumerator.Reset(); }
public TResult Current { get { return Mapping(Enumerator.Current); } }
object IEnumerator.Current { get { return Current; } }
}
internal static class MyExtensions
{
internal static IEnumerable<TResult> MySelect<TIn, TResult>(
this IEnumerable<TIn> enumerable,
Func<TIn, TResult> mapping)
{
return new SelectEnumerable<TIn, TResult>(enumerable, mapping);
}
}
The problem with your code is that Predicate<T> is a delegate that returns a boolean, which you're then trying to add to a List<object>.
Using a Func<T,object> is probably what you're looking for.
That being said, that code smells bad:
Converting to object is less than useful
Passing a delegate that maps T to an anonymous type won't help - you'll still get an object back which has no useful properties.
You probably want to add a TResult generic type parameter to your method, and take a Func<T, TResult> as an argument.
I'm trying to do a simple implementation of the Specification pattern in my domain layer.
If I have a static class full of specifications like this:
public static class FooSpecifications
{
public static Func<Foo, bool> IsSuperhuman
{
get
{
return foo => foo.CanShootLasersOutOfItsEyes && foo.CanFly;
}
}
}
Then I can do marvellous things like this:
IEnumerable<Foo> foos = GetAllMyFoos();
var superFoos = foos.Where(FooSpecifications.IsSuperhuman);
I can also add bool method to Foo to determine if a particular instance meets a specification:
public bool Meets(Func<Foo, bool> specification)
{
return specification.Invoke(this);
}
Given that Foo, like all my domain entities, extends DomainObject, is there a way I can put a generic implementation of Meets() into the DomainObject to save me implementing Meets() separately in every entity?
Something like this...
public abstract class DomainObj<T> // T - derived type
where T : DomainObj<T>
{
public bool Meets(Func<T, bool> specification)
{
return specification.Invoke((T) this);
}
}
public class Foo : DomainObj<Foo> {}
public class Bar : DomainObj<Bar> {}
Func<Foo, bool> foospec = x => true;
Func<Bar, bool> barspec = x => true;
var foo = new Foo();
var bar = new Bar();
foo.Meets(foospec);
foo.Meets(barspec); // won't compile because of mismatched types of spec and object instance
EDIT
Maybe it will be better to translate Meet method to extension. This will remove need in type parameter.
public abstract class DomainObj
{
}
public static class DomainObjExtensions
{
public static bool Meets<T>(this T obj, Func<T, bool> f)
where T : DomainObj
{
return f(obj);
}
}
public class Foo : DomainObj {}
public class Bar : DomainObj {}
Func<Foo, bool> foospec = x => true;
Func<Bar, bool> barspec = x => true;
var foo = new Foo();
var bar = new Bar();
foo.Meets(foospec);
foo.Meets(barspec); // error