2

I have a C# class that implements 2 IEnumerable interfaces. How can I access either interface from IronPython?

My class:

public class MyClass : IEnumerable<TypeA>, IEnumerable<TypeB>
{
    IEnumerator<TypeA> IEnumerable<TypeA>.GetEnumerator()
    {
        return _lstTypeA.GetEnumerator();
    }

    IEnumerator<TypeB> IEnumerable<TypeB>.GetEnumerator()
    {
        return _lstTypeB.GetEnumerator();
    }
}

I tried the following in Python, but although it runs without errors it does not return any elements from the IEnumerable interface:

x = MyClass()
xA = clr.Convert(x, IEnumerable[TypeA])
for y in xA: print y
3
  • 1
    What a badly designed class... Try to convince the author that he should fix it. Commented May 21, 2011 at 12:01
  • 1
    @CodeInChaos: I am the author. Please explain why this is badly designed, so I can improve it. Commented May 21, 2011 at 13:18
  • 2
    I guess he meant that it's not a good design when a class implements two different IEnumerable<T>, because to get the implicitly-implemented GetEnumerator() you need a cast (and BTW it's not clear why a class represents a collection of 2 different elements...). It's probably better to expose one of the two IEnumerable<T>s (the less important, or both, it depends...) as a property of that class. Commented May 21, 2011 at 14:21

3 Answers 3

5

I don't like your class design. In particular that you implement two different versions of IEnumerable<T> that return different members. Two versions that return the same members is slightly better, but I still don't like that much.

  1. Implementing IEnumerable so it's consistent with both IEnumerable<T>s isn't possible here. In particular that breaks the OfType and Cast linq methods.
  2. You get overload resolution problems almost everywhere. Methods like Select<T>(this IEnumerable<T> ...) don't know which IEnumerable to take.
  3. You can't use foreach on MyClass
  4. If both TypeA and TypeB are reference types the variance of IEnumerable<out T> comes back to bite you. Since both of them offer IEnumerable<T'> for all their common ancestors.
  5. It doesn't interact well with dynamically types languages
  6. A class being a two different collections at the same time rarely makes sense. It usually indicates that something went wrong in the mapping from concepts to classes.
  7. It's confusing and hard to understand. My intuition tells me it's evil and that I should burn it with fire :P

And Probably several more issues I didn't think of yet.


The work around is simple and clean: Have two separate enumerable properties.

public class MyClass
{
  public IEnumerable<TypeA> TypeAs{get{_lstTypeA.Select(x=>x)}};
  public IEnumerable<TypeB> TypeBs{get{_lstTypeB.Select(x=>x)}};
}
Sign up to request clarification or add additional context in comments.

1 Comment

Ok, I see why MyClass can be considered evil. Your suggestion to use two enumerable properties is a welcome improvement. Thank you!
4

You need to call methods and properties as you were using reflection (that is actually what it happens under the hood).

In your case you should do:

x = MyClass()
enumerator = IEnumerable[TypeA].GetEnumerator(x)

then you can loop over enumerator:

for y in enumerator:
   print y

2 Comments

Obvious once you see it... Works perfectly. Thanks a lot.
The link appears to be broken.
0

how i use specified interface

clr.AddReference('Platform.CardHost')
from Platform import CardHost
from Platform.CardHost import ICardHost

host = CardHost.CardHost.CreateInstance('session')
# ICardHost is interface
# inside C# 
# public interface ICardHost {
# IExtensionManager ExtensionManager { get; }
em = ICardHost.ExtensionManager.__get__(host) 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.