Hopefully this isn't a dupe, couldn't find anything related online
I'm getting a strange compile time error in the following extension method:
public static TCol AddRange<TCol, TItem>(this TCol e, IEnumerable<TItem> values)
where TCol: IEnumerable<TItem>
{
foreach (var cur in e)
{
yield return cur;
}
foreach (var cur in values)
{
yield return cur;
}
}
Error:
The body of 'TestBed.EnumerableExtensions.AddRange(TCol, System.Collections.Generic.IEnumerable)' cannot be an iterator block because 'TCol' is not an iterator interface type
Does this mean that generic constraints are not considered by the compiler when determining if a method qualifies for yield return use?
I use this extension method in a class which defines the collection using a generic parameter. Something like (in addition to a few type cast operators):
public class TestEnum<TCol, TItem>
where TCol : class, ICollection<TItem>, new()
{
TCol _values = default(TCol);
public TestEnum(IEnumerable<TItem> values)
{
_values = (TCol)(new TCol()).AddRange(values);
}
public TestEnum(params TItem[] values) : this(values.AsEnumerable()) { }
...
}
And in turn, used like (remember I have type cast operators defined):
TestEnum<List<string>, string> col = new List<string>() { "Hello", "World" };
string someString = col;
Console.WriteLine(someString);
Originally, my extension method looked like:
public static IEnumerable<TItem> AddRange<TItem>(this IEnumerable<TItem> e, IEnumerable<TItem> values)
{
...
}
Which compiles but results in:
Unhandled Exception: System.InvalidCastException: Unable to cast object of type '<AddRange>d__61[System.String]' to type 'System.Collections.Generic.List1[System.String]'.
Is there an alternative way to do this?
As requested, here's a small sample:
class Program
{
public static void Main()
{
TestEnum<List<string>, string> col = new List<string>() { "Hello", "World" };
string someString = col;
Console.WriteLine(someString);
}
}
public class TestEnum<TCol, TItem>
where TCol : class, ICollection<TItem>, new()
{
TCol _values = default(TCol);
public TestEnum(IEnumerable<TItem> values)
{
_values = (TCol)(new TCol()).AddRange(values);
}
public TestEnum(params TItem[] values) : this(values.AsEnumerable()) { }
public static implicit operator TItem(TestEnum<TCol, TItem> item)
{
return item._values.FirstOrDefault();
}
public static implicit operator TestEnum<TCol, TItem>(TCol values)
{
return new TestEnum<TCol, TItem>(values);
}
}
public static class EnumerableExtensions
{
public static IEnumerable<TItem> AddRange<TItem>(this IEnumerable<TItem> e, IEnumerable<TItem> values)
{
foreach (var cur in e)
{
yield return cur;
}
foreach (var cur in values)
{
yield return cur;
}
}
}
To repro the compile-time exception:
class Program
{
public static void Main()
{
TestEnum<List<string>, string> col = new List<string>() { "Hello", "World" };
string someString = col;
Console.WriteLine(someString);
}
}
public class TestEnum<TCol, TItem>
where TCol : class, ICollection<TItem>, new()
{
TCol _values = default(TCol);
public TestEnum(IEnumerable<TItem> values)
{
_values = (TCol)(new TCol()).AddRange(values);
}
public TestEnum(params TItem[] values) : this(values.AsEnumerable()) { }
public static implicit operator TItem(TestEnum<TCol, TItem> item)
{
return item._values.FirstOrDefault();
}
public static implicit operator TestEnum<TCol, TItem>(TCol values)
{
return new TestEnum<TCol, TItem>(values);
}
}
public static class EnumerableExtensions
{
public static TCol AddRange<TCol, TItem>(this TCol e, IEnumerable<TItem> values)
where TCol : IEnumerable<TItem>
{
foreach (var cur in e)
{
yield return cur;
}
foreach (var cur in values)
{
yield return cur;
}
}
}
Let's simplify:
static T M() where T : IEnumerable<int>
{
yield return 1;
}
Why is this illegal?
For the same reason that this is illegal:
static List<int> M()
{
yield return 1;
}
The compiler only knows how to turn M into a method that returns an IEnumerable<something>. It doesn't know how to turn M into a method that returns anything else.
Your generic type parameter T could be List<int> or any of infinitely many other types that implement IEnumerable<T>. The C# compiler doesn't know how to rewrite the method into one that returns a type it knows nothing about.
Now, regarding your method: what is the function of TCol in the first place? Why not just say:
public static IEnumerable<TItem> AddRange<TItem>(
this IEnumerable<TItem> s1, IEnumerable<TItem> s2)
{
foreach(TItem item in s1) yield return item;
foreach(TItem item in s2) yield return item;
}
Incidentally, this method already exists; it is called "Concat".
I'm not sure what are you trying to accomplish, your method certainly doesn't look like AddRange(), because it doesn't add anything to any collection.
But if you write an iterator block, it will return an IEnumerable<T> (or IEnumerator<T>). The actual run-time type it returns is compiler generated and there is no way to force it to return some specific collection, like List<T>.
From your example, AddRange() simply doesn't return List<T>, which is why you can't cast the result to that type. And there is no way to make iterator block return List<T>.
If you want to create a method that adds something to a collection, it probably means you need to call Add(), not return some other collection from the method:
public static void AddRange<T>(
this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
collection.Add(item);
}
In response to your comment to Eric Lippert's answer:
I hoped for a solution that would work against IEnumerable but will settle with one for ICollection.
public static void AddRange<TCol, TItem>(this TCol collection, IEnumerable<TItem> range)
where TCol : ICollection<TItem>
{
var list = collection as List<TItem>;
if (list != null)
{
list.AddRange(range);
return;
}
foreach (var item in range)
collection.Add(item);
}
I defined the method as void to mimic the semantics of List<T>.AddRange().
Related
First, I have this function that return true if the name is in the class:
public bool hasName<T>(List<T> Data, string name, Func<T, string> ClassName)
{
foreach (T entry in Data)
{
if (ClassName(entry) == name)
{
return true;
}
}
return false;
}
And it's called using:
hasName(Data, name, x => x.name)
The problem is, that i have another function that uses HasName but doesn't know about the field name.
public List<T> MergeClasses<T>(List<T> Pri, List<T> Sec, Func<T, string> ClassName)
{
List<T> result = new List<T>();
result.AddRange(Pri);
foreach (T entry in Sec)
{
if (!new Functions().hasName(result, ClassName(entry), x => x.name))
{
result.Add(entry);
}
}
return result;
}
How can i solve this?
You would need an interface or base-class to use as a generic constraint; for example:
interface IHazHame {
string Name {get;} // note property, not field
}
then your type with .name would need to implement that:
class Foo : IHazName {
// ...
}
and you can restrict your generic method to T that satisfy this:
public List<T> MergeClasses<T>(List<T> Pri, List<T> Sec, Func<T, string> ClassName)
where T : IHazHame
{
// ... x => x.Name
}
I need to implement this method :Reflectable reflect<T>(IEnumerable<T> src)
but i'm having troubles to get the expected output.
Hope someone can help me thanks.
Here the interface Reflectable:
interface Reflectable : IEnumerable<string> { Reflectable Prop(string propName);}
and the expected Output:
IEnumerable<Student> stds = //Students
IEnumerable<String> r1 = reflect(stds).Prop("Id");
IEnumerable<String> r2 = reflect(stds).Prop("Name").Prop("Id").Prop("Age");
IEnumerable<String> r3 = reflect(stds);
r1.ToList().ForEach(Console.Write); // {3213}{3124}{35454}...
r2.ToList().ForEach(Console.Write); // {Jose, 3213, 89}{Maria, 3124, 34}{Prominencia, 35454, 23}...
r3.ToList().ForEach(Console.Write); // {}{}{}...
I still think this idea of yours should be murdered in its sleep, or before birth...
public class ReflectionHelper<T>
: IEnumerable<string>
{
private string[] _properties;
private IEnumerable<T> _list;
public ReflectionHelper(IEnumerable<T> list, string[] properties)
{
_properties = properties;
_list = list;
}
public ReflectionHelper<T> Prop(string property)
{
return new ReflectionHelper<T>(_list, _properties.Concat(new string[]{ property}).ToArray());
}
public ReflectionHelper<T> Prop(string property)
{
return new ReflectionHelper<T>(_list, _properties.Concat(new string[] { property }).ToArray());
}
public static implicit operator List<string>(ReflectionHelper<T> helper)
{
return helper._list.Select(item => string.Join(",",
(from p in helper._properties
select typeof(T).GetProperty(p).GetValue(item, null)).ToArray())).ToList();
}
public IEnumerator<string> GetEnumerator()
{
return _list.Select(item => string.Join(",",
(from p in _properties
select typeof (T).GetProperty(p).GetValue(item, null)).ToArray()))
.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static class ReflectionHelperExtension
{
public static ReflectionHelper<T> Prop<T>(this IEnumerable<T> items, string property)
{
return new ReflectionHelper<T>(items, new string[] { property });
}
}
If I understand what you're achieving, extension methods would be a way to do it, and here is how:
// This class has to be static for extension methods to be detected
public static class MyExtensions
{
// using "this" before the first parameter will make it an extension of the type
public static IEnumerable<string> Prop<T>(this IEnumerable<T> enumerable, string propName)
{
var type = typeof(T);
// Note that this can throw an exception if the property is not found
var info = type.GetProperty(propName);
// Here are your students, considering that <T> is <Student>
foreach (var item in enumerable)
{
// return the value fromt the item, I'm using ToString here for
// simplicity, but since you don't know the property type in
// advance, you can't really do anything else than assumne its
// type is plain "object"
yield return info.GetValue(item).ToString();
}
}
}
One thing you won't be able to do is to chain them like #lomed said, since it returns an IEnumerable.
public static class EnumerableReflect
{
private static string OneElementReflect<T>(T e, PropertyInfo[] props)
{
var values = props.Select(x => x.GetValue(e).ToString());
return "{" + string.Join(", ", values)) + "}";
}
public static IEnumerable<string> enumerbleString<T>(this IEnumerable<T> collection, params string[] PropertysNames)
{
var props = PropertysNames.Select(x => typeof(T).GetProperty(x)).ToArray();
return collection.Select(x => OneElementReflect(x, props));
}
}
I have a utility method that processes a collection of strings, let's say:
public static string MyJoin(this IEnumerable<string> strings)
{
return string.Join(Environment.NewLine, strings);
}
I'd like to be able to also process IEnumerable<IEnumerable<string>> and IEnumerable<IEnumerable<IEnumerable<string>>> and so on, all of them in this way:
public static string MyJoin(this IEnumerable<IEnumerable<string>> strings)
{
return strings.Select(x => x.MyJoin()).MyJoin();
}
public static string MyJoin(this IEnumerable<IEnumerable<IEnumerable<string>>> strings)
{
return strings.Select(x => x.MyJoin()).MyJoin();
}
Is there any way I can elegantly express this without hardcoding all the possible levels I might want to use?
I've tried to do it with generics, but I just can't figure out the right constraints (if there are any).
I'd also like to avoid declaring a new type, if at all possible.
Performance, on the other hand, is not critical.
Based on Stefan's solution, simplified and compilation-fixed version
public static string MyJoin(this IEnumerable items)
{
if (items is IEnumerable<string>)
{
return string.Join(Environment.NewLine, (IEnumerable<string>)items);
}
if (items is IEnumerable<IEnumerable>)
{
return items.Cast<IEnumerable>().Select(x => x.MyJoin())).MyJoin();
}
throw new InvalidOperationException("Type is not a (nested) enumarable of strings");
}
Be careful with IEnumerable<T> and strings, because a string is an IEnumerable<T>, where T is char.
Static implementation using multiple overloads:
public static string MyJoin(this IEnumerable<IEnumerable<IEnumerable<string>>> items)
{
return items.SelectMany(x => x).MyJoin();
}
public static string MyJoin(this IEnumerable<IEnumerable<string>> items)
{
return items.SelectMany(x => x).MyJoin();
}
public static string MyJoin(this IEnumerable<string> strings)
{
return string.Join(Environment.NewLine, strings);
}
You cannot have a single generic method and "unwrap" the generic argument dynamically.
Implementation using reflection:
public static string MyJoin<T>(this IEnumerable<T> items)
{
if (typeof(T) == typeof(string)
{
return items.Cast<string>().MyStringJoin();
}
var innerIEnumerableType = typeof(T).GetInterfaces().FirstOrDefault(x => x.IsGeneric()
&& x.GetGenericType() == typeof(IEnumerable<>);
if (innerIEnumerableType != null)
{
// create generic method to
var method = typeof(ThisType).GetMethod("MyJoin", /* some flags */)
.MakeGenericMethod(innerIEnumerableType.GetGenericArguments().First())
// recursive call to generic method
return items.Select(x => (string)method.Invoke(null, x)).MyStringJoin();
}
throw new InvalidOperationException("Type is not a (nested) enumarable of strings")
}
public static string MyStringJoin(this IEnumerable<string> strings)
{
return string.Join(Environment.NewLine, strings);
}
To be honest, reflection isn't useful here. Why use generics, if it isn't typesafe anyway? At the end you could just as well use non-generic IEnumerable. It's much easier to implement. See Denis Itskovich's solution, he managed to write down what I actually tried to do.
Rather than having an IEnumerable of an unknown type, what you're really trying to do here is create a tree based structure. The most effective way of doing this is to create a Node class that can represent a value an its children.
public class Node
{
public Node(string value)
{
Value = value;
Children = Enumerable.Empty<Node>();
}
public Node(string value, IEnumerable<Node> children)
{
Value = value;
Children = children;
}
public string Value { get; private set; }
public IEnumerable<Node> Children { get; private set; }
}
This is now a much easier structure to traverse. Here is a general purpose tree traversal method which we can apply to this case:
public static IEnumerable<T> Traverse<T>(T item,
Func<T, IEnumerable<T>> childSelector)
{
var stack = new Stack<T>();
stack.Push(item);
while (stack.Any())
{
var next = stack.Pop();
yield return next;
foreach (var child in childSelector(next))
stack.Push(child);
}
}
var allValues = Traverse(rootNode, node => node.Children)
.Select(node => node.Value);
Partly inspired by Stefan's answer, I've reached a working solution that compiles without generics and (unfortunately) with mostly runtime type checking:
public static string MyJoin(this IEnumerable<string> strings)
{
return string.MyJoin(Environment.NewLine, strings);
}
public static string MyJoin(this IEnumerable<object> items)
{
if (items.All(x => x is string))
return items.Cast<string>().MyJoin();
if (items.All(x => x is IEnumerable<object>))
return items.Cast<IEnumerable<object>>().Select(x => x.MyJoin()).MyJoin();
throw new InvalidOperationException("The argument was not a nested enumerable of strings.");
}
Use the SelectMany extension method.
I'm working in a code base which has a lot of first class collections.
In order to ease using these collections with LINQ, there is an extension method per collection that looks like:
public static class CustomCollectionExtensions
{
public static CustomCollection ToCustomCollection(this IEnumerable<CustomItem> enumerable)
{
return new CustomCollection(enumerable);
}
}
With the accompanying constructors:
public class CustomCollection : List<CustomItem>
{
public CustomCollection(IEnumerable<CustomItem> enumerable) : base(enumerable) { }
}
This winds up being a bunch of boilerplate so I attempted to write a generic IEnumerable<U>.To<T>() so that we wouldn't have to keep generating these specific ToXCollection() methods.
I got as far as:
public static class GenericCollectionExtensions
{
public static T To<T, U>(this IEnumerable<U> enumerable) where T : ICollection<U>, new()
{
T collection = new T();
foreach (U u in enumerable)
{
collection.Add(u);
}
return collection;
}
}
Which has to be called like customCollectionInstance.OrderBy(i => i.Property).To<CustomCollection, CustomItem>()
Is there a way to avoid having to specify the CustomItem type so we can instead use customCollectionInstance.OrderBy(i => i.Property).To<CustomCollection>() or is this not something that can be done generically?
Something close to what you want:
public static class GenericCollectionExtensions
{
public sealed class CollectionConverter<TItem>
{
private readonly IEnumerable<TItem> _source;
public CollectionConverter(IEnumerable<TItem> source)
{
_source = source;
}
public TCollection To<TCollection>()
where TCollection : ICollection<TItem>, new()
{
var collection = new TCollection();
foreach(var item in _source)
{
collection.Add(item);
}
return collection;
}
}
public static CollectionConverter<T> Convert<T>(this IEnumerable<T> sequence)
{
return new CollectionConverter<T>(sequence);
}
}
Usage:
customCollectionInstance.OrderBy(i => i.Property).Convert().To<CustomCollection>();
I want to pass anonymous property using lambda to a generic function and access it there.
And how Do I access the property inside.
using (CommentsRepository commentsRepository = new CommentsRepository())
{
var comments = commentsRepository.GetAllComments();
Foo<Comment>(comments, 0,com=>com.ID); //Comment is an EF entity
}
public static void Foo<TObject>(IEnumerable<TObject> list, int iCurID, <Func<TObject, TProperty> property) where TObject : class
{
foreach (var cat in list.Where(/*How to access the property*/==iCurID)
{
int x = cat.property;
}
}
You just call the delegate:
public static void Foo<TObject>
(IEnumerable<TObject> list,
int iCurID,
Func<TObject, int> propertySelector) where TObject : class
{
foreach (var cat in list.Where(x => propertySelector(x) == iCurID))
{
}
}
Note that I had to change the type of the delegate to Func<TObject, int> as otherwise you couldn't compare it with iCurID.