Is it possible to implement several IEnumerable<T> in one class? - c#

I want to do something like this:
class T : IEnumerable<string>, IEnumerable<int>
{
string [] _strings = new string [20];
int[] _ints = new int[20];
public T() { }
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
foreach (string str in _strings)
yield return str;
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
foreach (int i in _ints)
yield return i;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
//Using in code:
T t = new T();
foreach (int i in t)
//to do something
foreach (string str in t)
//to do stuff
I desire to know Is there a way to realize It or not. May be there are tricks ?

You've nearly managed to implement both interfaces - you just need to change the non-generic implementation to show which generic implementation you're trying to delegate to. For example:
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<int>)this).GetEnumerator();
}
However, because you're implementing more than one IEnumerable<T> interface you'll need to cast in the foreach loop to show which one to use:
T t = new T();
foreach (int i in (IEnumerable<int>) t)
//to do something
foreach (string str in (IEnumerable<string>) t)
Personally I would strongly advise against doing this if possible though - it'll cause a lot of confusion for people reading your code.
See section 8.8.4 of the C# language specification for details of how the compiler treats the expression to iterate over in a foreach loop.
(By using "normal" interface implementation for one of the interfaces you could provide a sort of "default" - but I don't think that would really make it any better.)

I would suggest defining some struct types whose only field is an instance of your class type, initialized by the stuct's constructor, whose only public member would be GetEnumerator, and which implements IEnumerable<whatever> by calling an appropriate method on your base type. Then have your root class implement a member that returns a new instance of an appropriate struct.
For example, if your class Foo had a GetStringEnumerator method which returned a type that implements IEnumerable<String>, you could have Foo.AsStrings return a struct FooStringEnumerable whose GetEnumerator method called Foo.GetStringEnumerator.
Note that by having your enumerable thing be a struct rather than a class, you would avoid having to create an extra object instance in the common case where it is used in a "for-each" loop, since both vb and c# would duck-type the GetEnumerator method instead of casting to IEnumerable or IEnumerable<T>.

Related

How do I bundle existing Reset(), MoveNext(), and Current into a yield-based iterator in C#?

I have a simple class, MyClass, which already has the Reset(), MoveNext(), and Current pieces. But it doesn't provide an iterator, it just exposes those components.
I started with this:
public IEnumerator<MyClass> GetEnumerator()
{
Reset();
while (MoveNext())
yield return Current;
}
Which triggers the following error:
CS1579 foreach statement cannot operate on variables of type 'IEnumerator' because 'IEnumerator' does not contain a public instance definition for 'GetEnumerator'
I tried a bunch of other approaches, but no joy.
Would someone point me in the right direction?
Thanks!
I'm guessing your code does something like
foreach(var variable in collection.GetEnumerator())
{
//do some stuff
}
You can leave out the GetEnumerator call. If you class implements IEnumerable it wil be called automatically.
So just:
foreach(var variable in collection)
{
//do some stuff
}
Key points:
You should call foreach on the collection, not on the enumerator
Collection itself doesn't need to implement MoveNext and Current, the enumerator does
When you implement GetEnumerator() like IEnumerator<T> with yield statements, MoveNext and Current are implemented automatically, parameter type T shouldn't be exactly MyClass
Documentation on CS1579:
To iterate through a collection using the foreach statement, the
collection must meet the following requirements:
Its type must include a public parameterless GetEnumerator method whose return type is either class, struct, or interface type.
The return type of the GetEnumerator method must contain a public property named Current and a public parameterless method named
MoveNext whose return type is Boolean.
This is the example of simple collection of numbers from 1 to 5:
class MyCollection
{
public IEnumerator<int> GetEnumerator()
{
for (int index = 1; index <= 5; index++) {
yield return index;
}
}
}
And now you can iterate through it using foreach:
var collection = new MyCollection();
foreach(var element in collection) {
Console.Write(element);
}

List GetEnumerator return type does not match interface

In visual studio 2015, when I go to List.cs and see class declaration, I see only one method named GetEnumerator:
public Enumerator GetEnumerator();
On the other hand, the interface IEnumerable<T> and IEnumerable specifies that it must define method whose format is:
IEnumerator<T> GetEnumerator();
IEnumerator GetEnumerator();
This made me believe that interface method can be implemented even though the reuturn type does not excatly match. Although, that turned out to be wrong when I tried.
What is happening here?
If you look at the source you will see two different GetEnumerator methods:
public Enumerator GetEnumerator() {
return new Enumerator(this);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new Enumerator(this);
}
The second one is only used if you are accessing the object through the IEnumerator interface. They both do use the same underlying implementation however.
[Serializable]
public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
{
...
}
You can still get to the strongly typed version as follows:
var exampleList = new List<string>();
var enumerator1 = ((IEnumerable<string>)exampleList).GetEnumerator()
var enumerator2 = (IEnumerable<string>) exampleList.GetEnumerator()
For enumerator1 you are casting the list to use the GetEnumerator() method for the IEnumerable interface. For enumerator2 you are relying on the fact that the same implementation is used in in each and therefore you can just cast the enumerator.
The interface is implemented explicitly. The method you're seeing is not the interface implementation, it's a separate method for the class.

Diamond Syntax in C#

Java 7 now has this "diamond syntax" where I can do things like ArrayList<int> = new ArrayList<>();
I'm wondering if C# has a similar syntax that I can take advantage of.
For example, I have this part of a class:
class MyClass
{
public List<double[][]> Prototypes; // each prototype is a array of array of doubles
public MyClass()
{
Prototypes = new List<double[][]>; // I'd rather do List<>, in case I change the representation of a prototype later
}
}
Does anyone know if this is possible, and if so, how I might go about using it?
No, there's nothing quite like the diamond syntax in C#. The closest you could come would be to have something like this:
public static class Lists
{
public static List<T> NewList<T>(List<T> ignored)
{
return new List<T>();
}
}
Then:
public MyClass()
{
ProtoTypes = Lists.NewList(ProtoTypes);
}
That just uses normal generic type inference for methods to get T. Note that the value of the parameter is completely ignored - it's only the compile-time type which is important.
Personally I think this is pretty ugly, and I'd just use the constructor directly. If you change the type of ProtoTypes the compiler will spot the difference, and it won't take long at all to fix it up...
EDIT: Two alternatives to consider:
A similar method, but with an out parameter:
public static class Lists
{
public static void NewList<T>(out List<T> list)
{
list = new List<T>();
}
}
...
Lists.NewList(out ProtoTypes);
The same method, but as an extension method, with the name New:
public static class Lists
{
public static List<T> New<T>(this List<T> list)
{
return new List<T>();
}
}
...
ProtoTypes = ProtoTypes.New();
I prefer the first approach to either of these :)
As Jon Skeet said and Eric Lippert backed up, constructors for generic classes in C# cannot infer their types from their parameters or the type of the variable to which the construction is assigned. The go-to pattern when this type of behavior is useful is usually a static generic factory method, which can infer its own generic type from those of its parameters. Tuple.Create() is an example; give it any list of parameters up to 8, and it will create a strongly-typed generic Tuple with those parameters as the data fields. This doesn't work out well for your case, however.
When the variable will be local, consider doing it the other way around; use variable type inference, via the var keyword:
var Prototypes = new List<double[][]>();
This is how the C# team decided to cut down on typing when instantiating variables. Locals are created - and change - much more often than instance variables, and this approach makes C# code look a little more like JavaScript.
As Jon showed, it's possible to hide the mess, but you'll create more of a mess in the process. Here's another possibility using .NET 3.5/4.0's Expression features:
public static string GetName(this Expression<Func<object>> expr)
{
if (expr.Body.NodeType == ExpressionType.MemberAccess)
return ((MemberExpression) expr.Body).Member.Name;
//most value type lambdas will need this because creating the Expression
//from the lambda adds a conversion step.
if (expr.Body.NodeType == ExpressionType.Convert
&& ((UnaryExpression)expr.Body).Operand.NodeType
== ExpressionType.MemberAccess)
return ((MemberExpression)((UnaryExpression)expr.Body).Operand)
.Member.Name;
throw new ArgumentException(
"Argument 'expr' must be of the form ()=>variableName.");
}
public static void InitializeNew(this object me, params Expression<Func<T>>[] exprs)
where T:new()
{
var myType = me.GetType();
foreach(var expr in exprs)
{
var memberName = expr.GetName()
var myMember = myType.GetMember(memberName,
BindingFlags.Instance|BindingFlags.Public
|BindingFlags.NonPublic|BindingFlags.FlattenHierarchy,
MemberTypes.Field|MemberTypes.Property);
if(myMember == null)
throw new InvalidOperationException(
"Only property or field members are valid as expression parameters");
//it'd be nice to put these under some umbrella of "DataMembers",
//abstracting the GetValue/SetValue methods
if(myMember.MemberType == MemberTypes.Field)
((FieldInfo)myMember).SetValue(me, new T());
else
((PropertyInfo)myMember).SetValue(me, new T());
}
}
//usage
class MyClass
{
public List<double[][]> list1;
public List<double[][]> list2;
public MyOtherObject object1;
public MyClass()
{
this.Initialize(()=>list1, ()=>list2);
this.Initialize(()=>object1); //each call can only have parameters of one type
}
}
The implication is obvious here; it's more trouble than it's worth.
To explain why I seemingly just had this laying around; the above is an adaptation of a method I use to throw ArgumentNullExceptions based on passed parameters, which requires the values to be encapsulated within Expressions in order to retain the names of the actual parameters from the calling method. In that situation, the complexity behind the scenes is reduced since all I need in the main helper is a check for null, and the added complexity saves me a lot more than I spend, by allowing me to one-line my null checks in every method and constructor of the codebase.
I recommend ReSharper as a long-term solution to reducing this typing. When the type of an assignment target is known (as it is for instance fields and properties), and you type = new, ReSharper will pop up a suggestion for the type of the constructor, and auto-fill it for you if you want. If you change either the type or constructor afterward, R# will flag the assignment as inconsistent, and you can tell R# to change whichever one you want to match the other.
If you just want to reduce code verbosity there is an opposite shortand syntax: the var operator
Old: List<int> intList = new List<int>();
New: var intList = new List<int>();
At least you write List only once

Implement same Generic Interface 2 times with different Generic parameter

I had to implement 2 interface same time with different generic parameter as below. I get confused enough about it. I had no idea which one of them iterate itself in foreach. Now i understand first one is implicitly choosen.
I have tried new BarList().GetEnumerator() but i can not specify type parameter on method level.
Only solution i have found it that casting it to interface like(new BarList() as IEnumerable<string>)
After confusing about it enough. I just wanted to know that this design is not really good idea ? I have to avoid to implement same generic interface one more time ?
class Program
{
static void Main(string[] args)
{
foreach (var item in new BarList())
{
}
}
}
class BarList: IEnumerable<string>, IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Edit:
Let me explain why i am going in this way.
I had to Implement IPagedList<T> interface which is inherited from IList<T>. I wanted to write extension method which convert it to My view model. like below
GetAll().ToPagedList(pageindex);//which is returning IPagedList Then i wanted to use it like below;
GetAll().ToPagedList(pageindex).ToViewModel<T,TViewModel>();
For achieve this I tried to return IPagedList<ViewModel> by that extension method.In that case I have to implement IPagedList 2 times with different parameter. But this strategy made confusing things. This is reason of it.
This seems a bit confusing. Why not make it explicit what is happening by adding the enumerators as properties rather than implementing them on the class. For example,
class ProductCollection
{
public IEnumerable<int> EnumerateTheInts { get { //code to produce enumerator }}
public IEnumerable<string> EnumerateTheStringss { get { //code to produce enumerator }}
}
It isn't always bad to implement an open generic interface twice on an object. For example, IHandle could be implemented by a class which can handle two types of T. However, I would find it confusing to implement IEnumerable twice, because you might not enumerate the type you expect in a for-each or in LINQ. Same reasoning for implementing more than one indexer incidentally. The type of your indexer will determine your result, which I can testify to being extremely confusing!
The compiler is picking the IEnumerator<int> GetEnumerator method by following the rules in 8.8.4 of the C# language specification which first looks for an accessible GetEnumerator() method on the BarList type. The only one of those which is available is the one returning IEnumerator<int>.
If you had made that method use explicit interface implementation as well, then it would have gone onto the later stages of section 8.8.4, which states that if there is more than one type T such that there is an implicit conversion from the expression type (BarList here) to IEnumerable<T> then an error is produced.
I would say this is a confusing design - I would probably add properties or methods to retrieve appropriate "views" on the data.
I'd avoid it. However, it depends on your usage.
It will be okay if you just wanted to pass the instance into a function that expects a IEnumerable<string> parameter explicitely:
you won't have to cast
the function won't even 'see' the other interfaces implemented, so there isn't any confusion.
YMMV
Your current design is confusing. While you have not provided any information about the nature of the collection itself, from the name, I can assume you are supposed to iterate over a bunch of products. Perhaps, you should simply have a class of type Product with a string property and an int property and simply return an IEnumerable<Product> instead.
This way, with LINQ extension methods, you can compose the IEnumerable<T> object you actually mean with:
collection.Select(product => product.IntegerProperty)
collection.Select(product => product.StringProperty)
Of course, you can provide helper methods inside the object as well:
class ProductCollection : IEnumerable<Product> {
public IEnumerable<Product> GetEnumerator() {
// ... return Product objects here.
}
public IEnumerable<int> AsIntegerCollection() {
// yield the integer collection here
}
public IEnumerable<string> AsStringCollection() {
// yield the string collection here
}
}
What are these collections of string and ints? I suppose they mean something in relation with the Product (for example Name, Id, etc...) so I would rather do something like this:
class ProductCollection : IEnumerable<Product>
{
public IEnumerator<Product> GetEnumerator()
{
...
}
public IEnumerator<string> ProductNames // a helper to enumerate product names
{
...
}
public IEnumerator<int> ProductIds // a helper to enumerate product ids
{
...
}
}

How do I detect that an object is a generic collection, and what types it contains?

I have a string serialization utility that takes a variable of (almost) any type and converts it into a string. Thus, for example, according to my convention, an integer value of 123 would be serialized as "i:3:123" (i=integer; 3=length of string; 123=value).
The utility handles all primitive type, as well as some non-generic collections, like ArrayLists and Hashtables. The interface is of the form
public static string StringSerialize(object o) {}
and internally I detect what type the object is and serialize it accordingly.
Now I want to upgrade my utility to handle generic collections. The funny thing is, I can't find an appropriate function to detect that the object is a generic collection, and what types it contains - both of which pieces of information I need in order to serialize it correctly. To date I've been using coding of the form
if (o is int) {// do something}
but that doesn't seem to work with generics.
What do you recommend?
EDIT: Thanks to Lucero, I've gotten closer to the answer, but I'm stuck at this little syntactical conundrum here:
if (t.IsGenericType) {
if (typeof(List<>) == t.GetGenericTypeDefinition()) {
Type lt = t.GetGenericArguments()[0];
List<lt> x = (List<lt>)o;
stringifyList(x);
}
}
This code doesn't compile, because "lt" is not allowed as the <T> argument of a List<> object. Why not? And what is the correct syntax?
Use the Type to gather the required information.
For generic objects, call GetType() to get their type and then check IsGenericType to find out if it is generic at all. If it is, you can get the generic type definition, which can be compared for instance like this: typeof(List<>)==yourType.GetGenericTypeDefinition().
To find out what the generic types are, use the method GetGenericArguments, which will return an array of the types used.
To compare types, you can do the following: if (typeof(int).IsAssignableFrom(yourGenericTypeArgument)).
EDIT to answer followup:
Just make your stringifyList method accept an IEnumerable (not generic) as parameter and maybe also the known generic type argument, and you'll be fine; you can then use foreach to go over all items and handle them depending on the type argument if necessary.
Re your conundrum; I'm assuming stringifyList is a generic method? You would need to invoke it with reflection:
MethodInfo method = typeof(SomeType).GetMethod("stringifyList")
.MakeGenericMethod(lt).Invoke({target}, new object[] {o});
where {target} is null for a static method, or this for an instance method on the current instance.
Further - I wouldn't assume that all collections are a: based on List<T>, b: generic types. The important thing is: do they implement IList<T> for some T?
Here's a complete example:
using System;
using System.Collections.Generic;
static class Program {
static Type GetListType(Type type) {
foreach (Type intType in type.GetInterfaces()) {
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(IList<>)) {
return intType.GetGenericArguments()[0];
}
}
return null;
}
static void Main() {
object o = new List<int> { 1, 2, 3, 4, 5 };
Type t = o.GetType();
Type lt = GetListType(t);
if (lt != null) {
typeof(Program).GetMethod("StringifyList")
.MakeGenericMethod(lt).Invoke(null,
new object[] { o });
}
}
public static void StringifyList<T>(IList<T> list) {
Console.WriteLine("Working with " + typeof(T).Name);
}
}
At the most basic level, all generic lists implement IEnumerable<T>, which is in itself a descendant of IEnumerable. If you want to serialize a list, then you could just cast it down to IEnumerable and enumerate the generic objects inside them.
The reason why you can't do
Type lt = t.GetGenericArguments()[0];
List<lt> x = (List<lt>)o;
stringifyList(x);
is because generics still need to be statically strong typed, and what you're trying to do is to create a dynamic type. List<string> and List<int>, despite using the same generic interface, are two completely distinct types, and you can't cast between them.
List<int> intList = new List<int>();
List<string> strList = intList; // error!
What type would stringifyList(x) receive? The most basic interface you could pass here is IEnumerable, since IList<T> doesn't inherit from IList.
To serialize the generic list, you need to keep information on the original Type of the list so that you can re-create with Activator. If you want to optimize slightly so that you don't have to check the type of each list member in your stringify method, you could pass the Type you've extracted from the list directly.
I did not want to accept that there is no way to cast to List<lt>. So I came up with using a List<dynamic>.
But since i need it for all types of IEnumerables, my solution looks like this:
object o = Enumerable.Range(1, 10)
.Select(x => new MyClass { Name = $"Test {x}" });
//.ToList();
//.ToArray();
if (o.IsIEnumerableOfType<IHasName>(out var items))
{
// here you can use StringifyList...
foreach (var item in items)
{
Console.WriteLine(item.Name);
}
}
static class Ext
{
public static bool IsIEnumerableOfType<T>(this object input,
[NotNullWhen(true)] out IEnumerable<T>? values)
{
var innerType = input.GetType()
.GetInterfaces()
.FirstOrDefault(x =>
x.IsGenericType
&& x.GetGenericTypeDefinition() == typeof(IEnumerable<>))?
.GetGenericArguments()[0];
if (typeof(T).IsAssignableFrom(innerType))
{
values = ((IEnumerable<object>)input).OfType<T>();
return true;
}
values = null;
return false;
}
}
class MyClass : IHasName
{
public string Name { get; set; } = "";
}
Features:
You can use any Type of IEnumerable (inkl. Arrays and Lists)
Your can not only specify the actual class but its interface
It does not give any warnings due to the use of [NotNullWhen(true)]
Update:
For Dictionaries it's nearly the same code. Just change IEnumerable to IDictionary and use
Type keyType = t.GetGenericArguments()[0];
Type valueType = t.GetGenericArguments()[1];
to get the key and value type.
Update based on #Enigmativity comments
The use of dynamic is not needed. object is fine and is safer.
– Enigmativity
Yes, you can use IEnumerable<object> in this case.
You also only need this test: if (typeof(IEnumerable<object>).IsAssignableFrom(input.GetType())). –
Enigmativity
And, when you really get down to it you can just write if (o is IEnumerable<IHasName> items) in the main code. – Enigmativity
This only works for IEnumerable, but if you want to work with a list and the list should be of type IList<IHasName> It will not work anymore. So my solution is more versatile. (The accepted answer uses IList and inspired me)
I tried this with a List and it did not enter the if-statement:
object x = new List<MyClass>();
if (x is IList<IHasName> list)
{
for (int i = 0; i < list.Count; i++)
{
list[i] = newItems.ElementAt(i);
}
}
Use case:
if (value.IsListOfType<UpdatableBase>(out var list))
{
for (int i = 0; i < list.Count; i++)
{
list[i] = newItems.ElementAt(i);
}
}
The extension methode looks like:
public static bool IsListOfType<T>(this object input, [NotNullWhen(true)] out IList<T>? values)
{
Type? innerType = input.GetType()
.GetInterfaces()
.FirstOrDefault(x =>
x.IsGenericType
&& x.GetGenericTypeDefinition() == typeof(IList<>))?
.GetGenericArguments()[0];
if (typeof(T).IsAssignableFrom(innerType))
{
values = ((IList<object>)input).OfType<T>().ToList();
return true;
}
values = null;
return false;
}
But, finally, this question is about using a run-time type, not a
compile time one. – Enigmativity
My solution is suitable for the use case described in the question. He can use object or what ever (base) type his serializer is able to stringify as T-parameter.

Categories

Resources