I write 2 class inherit each other and each implement IEnumerable with difference generic type
Like this
```C#
public class A : IEnumerable
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
public class B : A, IEnumerable
{
public new IEnumerator
{
throw new NotImplementedException();
}
}
////
static void Test()
{
var a = new A();
var b = new B();
a.Select((item,i) => i);
b.Select((item,i) => i);
}
```
Instance from A work fine but B cannot use all generic function in System.Linq

It seem B was seen by compiler that it is just IEnumerable but not IEnumerable<string>. It still have Cast<> and OfType<> exposed

It's because B implements both IEnumerable<object> and IEnumerable<string> so it's not possible for the compiler to resolve which generic type arguments to use with the extension method. The error message isn't quite clear about that but I think that's the fallback message anytime extension methods fail to resolve.
If you tried to call the extension method directly with the generic type argument inferred you'd get the following error message:
/*
error CS0411: The type arguments for method
'Enumerable.Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>)'
cannot be inferred from the usage.
Try specifying the type arguments explicitly.
*/
Enumerable.Select(b, (item, i) => i);
Calling with the generic type arguments explicitly specified does work:
Enumerable.Select<string, int>(b, (item, i) => i);
I think compiler should select the latest implementation as default. Just like foreach
When I foreach B it return string not object so extension method should be the same
I think when we implement same interface on parent and derived class. It explicit enough to state that later implementation would be first priority to resolve. Like using new keyword to override function with the same name. And to get previous implementation then we need to explicitly specified generic type
Or should we have something like new on interface declaration?
```C#
public class A : IEnumerable
{
public IEnumerator
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
public class B : A,new IEnumerable
{
public new IEnumerator
{
throw new NotImplementedException();
}
}
```
@Thaina
When I foreach
Bit returnstringnotobjectso extension method should be the same
That's not how foreach works. It doesn't care about any inheritance tree, it cares about whether the types fit the enumerable pattern. All the compiler cares about is whether there is an accessible GetEnumerator method. You don't even have to implement IEnumerable or IEnumerable<T>.
If you were to reverse your example and have GetEnumerator public on A and explicitly implemented on B then foreach would iterate over IEnumerator<object> instead. The compiler would implicitly insert casts from object to string so that detail might not be noticed unless the two enumerators returned different values.
However, if both A and B explicitly implement all of the members of IEnumerable<string> and IEnumerable<object> then trying to foreach over B would result in a compiler error since the compiler cannot determine which of the two interfaces it should enumerate.
Like using
newkeyword to override function with the same name. And to get previous implementation then we need to explicitly specified generic type
To the CLR, IEnumerable<object> and IEnumerable<string> are different types. There is no support for variance in interface implementation between a base class and its derived classes. Although that would be interesting.
I know foreach does not look at interface. I just mean what I get from foreach should be the same thing I got from Linq
So, I think generic extension method resolver should just look at latest type it was implemented in the chain first. What could be problem on this assumption?
Why not solve this by making A generic as well?
//maybe make this class abstract if it contains shared logic
//for other derived types and have a separate class
//inheriting A<object> if you need it
public class A<T> : IEnumerable<T>
{
//....
}
public class B : A<string>
{
//....
}
@Joe4evr Because actually what I extend from is newtonsoft JArray and JObject which I don't wrote it myself
Currently I just write my own extension method For<T>(this JArray) to just convert it. Which is not clean in my opinion
@Thina Why do you use your own implementation instead of Cast<T>?
@eyalsk Because I'm not sure what will happen when we call JArray.Cast<int>() or JObject.Cast<MyOwnClass>(). I don't know how JArray implement
Also I was create my own IEnumerable<KeyValuePair<string,T>> JObject.For<T>() because JObject itself return JToken
@Thaina JObject, JArray and JToken implement Value<T> and Values<T>, can't you use them? I'm not sure what you're doing exactly or trying to do but conversion between types seems like a very basic feature that such a library should have and it does. :)
@eyalsk In short. Please believe me that I have my own specific logic that really need to implement it like this and all those easy workaround does not work. Please believe me that I already try most of those easy option
To clarify it. I try to make a class extended from JArray and JObject as a wrapper for intellisense. All of the property in that class only get/set
```C#
public class MyClass : JObject
{
public MyClass(JObject jobj) : base(jobj) { }
public int number { get { return this.Get("value",0); } set { return this["value"] = value; } }
public int? value { get { return this.TryGet
}
With this way of code I will get intellisense for property I know while still maintain all original json data that may contain extra property
But I implement my own `Get` function because whenever the thing I call `Get` was derived from JArray or JObject, it will replace that property. Which `Value<>` and `Values<>` don't do it for me
```C#
public class MyParentClass : JObject
{
public MyParentClass(JObject jobj) : base(jobj) { }
public MyClass child { get { return this.Get<MyClass>("child"); } set { return this["child"] = value; } }
}
public static class ExtJson
{
public T Get<T>(this JObject jobj,string key)
{
var obj = jobj[key].ToObject<T>();
if(obj is JObject)
jobj[key] = obj as JObject;
return obj;
}
}
And so I wrap all json system with me own Get
but the main issue came when I just want to make MyClass being Dictionary. that's why I need to implement my own For to wrap everything around it
Well this is frustrate me but I already request feature intellisense on dynamic but you just mess with that issue. And so for now I need to workaround like this. But even have so much hard time with it it still not a neat way
I will not need anything like this if I could just make dynamic intellisense
@Thaina
Well this is frustrate me but I already request feature intellisense on dynamic but you just mess with that issue. And so for now I need to workaround like this. But even have so much hard time with it it still not a neat way
I didn't try to mess with you or make a mess, I just wrote my opinion and regardless to what I wrote the issue #15974 is actually marked with Feature Request and Backlog.
I make mistakes, I write things that sometimes don't make sense and people here help or correct me, you shouldn't feel frustrated, you should have fun and appreciate it. :)
I will not need anything like this if I could just make dynamic intellisense
And it might happen. :)
Most helpful comment
@Thaina
That's not how
foreachworks. It doesn't care about any inheritance tree, it cares about whether the types fit the enumerable pattern. All the compiler cares about is whether there is an accessibleGetEnumeratormethod. You don't even have to implementIEnumerableorIEnumerable<T>.If you were to reverse your example and have
GetEnumeratorpublic onAand explicitly implemented onBthenforeachwould iterate overIEnumerator<object>instead. The compiler would implicitly insert casts fromobjecttostringso that detail might not be noticed unless the two enumerators returned different values.However, if both
AandBexplicitly implement all of the members ofIEnumerable<string>andIEnumerable<object>then trying toforeachoverBwould result in a compiler error since the compiler cannot determine which of the two interfaces it should enumerate.To the CLR,
IEnumerable<object>andIEnumerable<string>are different types. There is no support for variance in interface implementation between a base class and its derived classes. Although that would be interesting.