So I'm coming from Java and is a bit confused on how to use Generics with C#. I have lambda function that should take a list and predicate (of varying object types). When I specify that I want to use generic, the compiler complains that it cannot find T. This is my lambda:
private List<T> LoopCompareLambda(List<T> list, Predicate<T> condition)
{
List<T> returnList = new List<T>();
foreach (T sensor in list)
{
if (condition(sensor))
{
returnList.Add(sensor);
}
}
return returnList;
}
Try
private List<T> LoopCompareLambda<T>(List<T> list, Predicate<T> condition)
The <T> must be after the method name and before the (.
Note that the signature could be (with the code you wrote):
private static List<T> LoopCompareLambda<T>(IEnumerable<T> list, Predicate<T> condition)
And in .NET there is a strong preference for using Func<T, bool> instead of Predicate<T>
private static List<T> LoopCompareLambda<T>(IEnumerable<T> list, Func<T, bool> condition)
Change the signiture of your method to
private List<T> LoopCompareLambda<T>(List<T> list, Predicate<T> condition)
You have to add your generic type to the method. You can use multiple generics in one method and add conditions like
private List<T> LoopCompareLambda<T>(List<T> list, Predicate<T> condition) where T : class, new()
as well.
Your class needs to be generic.
class MyGenericClass<T>
{
...
}
Related
So i have this function that return element from collection based on condition
public static T Search<T>(IEnumerable<T> source, Func<T, bool> filter)
{
return source.FirstOrDefault(filter);
}
And i want to convert this to return all the elements form my collection that mach my condition.
so instead of change the function signature to public static IEnumerable<T> Search<T>(IEnumerable<T> source, Func<T, bool> filter)
What i need to changed inside my function ?
Use Where instead of FirstOrDefault
public static IEnumerable<T> Search<T>(IEnumerable<T> source, Func<T, bool> filter)
{
return source.Where(filter);
}
Use the Where method instead of FirstOrDefault
Wasn't really sure how to phrase the title.
What I am trying to achieve is a deep clone system for IEnumerable<T>s where T:ICloneable.
I have written the, as-yet untested, method below which I believe should work:
public static IEnumerable<T> DeepClone<T>(this IEnumerable<T> source) where T:ICloneable
{
return source.Select(s => (T) s.Clone());
}
However, this returns an IEnumerable<T> (as one would expect) and I am curious as to whether or not it is possible (without causing an unacceptable overhead) to return the base type of the IEnumerable<T> instead.
For example, running List<int>.DeepClone() would return a new, cloned List<int> and running int[].DeepClone() would return a new, cloned int[].
I know that I can quite easily just cast my IEnumerables after calling this method, but I'm hoping to be able to avoid this.
There is also the option of creating a whole load of overloads, one for each IEnumerable but if it's possible to I'd like to avoid this.
You will need to build explicit methods for the concrete types you want to support (List, arrays etc).
An example:
public static List<T> DeepClone<T>(this List<T> source) where T : ICloneable
{
return source.Select(s => (T)s.Clone()).ToList();
}
Alternatively, use an approach like:
public static IEnumerable<T> DeepClone<T>(this IEnumerable<T> source) where T : ICloneable
{
var result = source.Select(s => (T)s.Clone());
if (source is List<T>)
{
return result.ToList();
}
return result;
}
I am trying to create an extension method that "extends" on an IEnumerable of a type, accepts an expression as a parameter and returns an IEnumerable of the same type.
public static IEnumerable<T> CustomExtension<T>(this IEnumerable<T> cities, Expression<Func<T, bool>> predicate)
{
return Enumerable.Where(cities, predicate);
//the line above is wrong, doesn't compile, but it explains my intentions...
}
Then call it like so:
var bigCities = cities.CustomExtension(c => c.occupants >= 1000000);
OR
var coldCities = cities.CustomExtension(c => c.avgTemp <= 20);
NOTE: It isn't just for "city" objects, the plan is to keep it generic so I can use the same method on similar types
Thanks in advance...
public static IEnumerable<T> CustomExtension<T>(this IEnumerable<T> cities, Func<T, bool> predicate)
{
return cities.Where(x => predicate(x));
}
Here's what I have
private readonly Dictionary<Type, List<object>> _cache;
public IList<T> Get<T> (Expression<Func<T, bool>> criteria)
{
return _cache[typeof(T)].Where (criteria);
}
The compiler complains (rightly) that it cannot convert from object to T.
How should I proceed from there?
Solution
return _cached[type].AsQueryable().Cast<T>().Where (criteria).ToList()
The idea is to have the List as an IQueryable and then I could Cast...
Use the .Cast<>() Extension Method:
private readonly Dictionary<Type, List<object>> _cache;
public IList<T> Get<T> (Expression<Func<T, bool>> criteria)
{
return _cache[typeof(T)].Cast<T>().Where (criteria).ToList();
}
If you aren't absolutely sure that all elements are of type T, you can use .OfType<T>() instead (which skips elements that cannot be cast)
Edit You'll also need to use .OfType<T>() when T is a valuetype (struct).
Edit Since your comment mentioned IQueryable, this could help:
return _cache[typeof(T)].AsQueryable().Cast<T>().Where (criteria).ToList();
private readonly Dictionary<Type, List<object>> _cache;
public IList<T> Get<T> (Expression<Func<T, bool>> criteria)
{
return _cache[typeof(T)].Cast<T>().Where(criteria).ToList();
}
Ok, fixed it:
return _cached[type].AsQueryable().Cast<T>().Where (criteria).ToList()
The idea is to have the List as an IQueryable and then I could Cast...
may be building the expression dynamically and then compile it is a better option. here is a sample:
Expression<Func<TestClass, bool>> query = LambdaBuilder.BuildQuery(queryItems);
Func<TestClass, bool> compiledExpression = query.Compile();
var results = data.Where(compiledExpression);
You may read my article on it
Do you really need the argument to be of Expression>? Of not this should do the trick:
private readonly Dictionary<Type, List<object>> _cache;
public IList<T> Get<T>(Func<T,bool> criteria)
{
return _cache[typeof(T)].Cast<T>().Where(criteria).ToList();
}
I have an Entity Framework 'TrackableCollection' and I want to sort it by an attribute. I have tried treating it like an IEnumerable and calling
TrackableCollection<Something>.OrderBy(q=>q.SomeValue);
but it throws an exception "Cannot implicitly covert type IOrderedEnumerable to TrackableCollection.
Anyone know how to sort a TrackableCollection?
The code example Shiv Kumar refers to does not work - it doesn't compile, and even after you factor things up (like implementing generics in a lot of places), it works but buggy, since the code calls collection.Move which causes a "Index must be within the bounds of the List" exception in certain cases.
The code below works correctly. The coders of STE (Self Tracking Entities) should had implemented that themselves... This is the correct code:
public static class Extensions
{
public static void Sort<T>(this TrackableCollection<T> collection, Comparison<T> comparison)
{
var comparer = new Comparer<T>(comparison);
List<T> sorted = collection.OrderBy(x=>x, comparer) .ToList();
collection.Clear();
for (int i = 0; i < sorted.Count(); i++)
collection.Add(sorted[i]);
}
}
class Comparer<T> : IComparer<T>
{
private Comparison<T> comparison;
public Comparer(Comparison<T> comparison)
{
this.comparison = comparison;
}
public int Compare(T x, T y)
{
return comparison.Invoke(x, y);
}
}
You use this code as in the previous example:
YourTrackableCollectionName.Sort((x, y) => x.YourFieldName.CompareTo(y.YourFieldName));
This is a simplifed version of Ofer Zeligs code that uses a keySelector func (like LINQ OrderBy) instead of an explicit Comparison delegate. Since it only uses Clear() and Add() it can be called on any Collection object (like an ObservableCollection or a TrackableCollection).
public static void Sort<TSource, TKey>(this Collection<TSource> source, Func<TSource, TKey> keySelector)
{
var sorted = source.OrderBy(keySelector).ToList();
source.Clear();
foreach (var item in sorted)
source.Add(item);
}
It's used like this:
list.Sort(person => person.Name);
If you're using this on a TrackableCollection (STE) you might want to make sure you haven't started tracking changes before sorting the list.