clankill3r
clankill3r

Reputation: 9583

static method with generics

In java I have a class:

static public class PCB_Node<T extends PCB_Node<T>> implements Iterable<T> {
    public T parent;
    public T first_child;
    public T next_brother;
    
    public Iterator<T> iterator() {
        return get_iterator((T)this);
    }

}


static public <T extends PCB_Node<T>> Iterator<T> get_iterator(T e) {
    ...
}

I attempt to do port this to c#, in which I have very little experience.

I defined the class like this:

public class PCB_Node<T> where T : PCB_Node<T>, IEnumerable<T> {
    public T parent;
    public T first_child;
    public T next_brother;

    public IEnumerator<T> GetEnumerator() {
        return get_iterator((T)this); // << not sure about this, but that also depends on if it is possible
    }
}

I have problems with doing the following java line in c#: static public <T extends PCB_Node<T>> Iterator<T> get_iterator(T e) {. And I'm not sure if it's even possible, cause so far, I can't find anything about it. I know I can implement GetEnumerator in the class itself instead of redirecting it to some static method, but I prefer it this way.

I guess this is what I want:

static public IEnumerable<T> get_iterator(T e) where T : PCB_Node<T> {

Is something like that possible?

Upvotes: 0

Views: 147

Answers (2)

Johnathan Barclay
Johnathan Barclay

Reputation: 20373

Firstly, your class declaration is not correct.

Here you are saying that T must be a PCB_Node<T> and implement IEnumerable<T>:

public class PCB_Node<T> where T : PCB_Node<T>, IEnumerable<T>

Whereas you want PCB_Node<T> to implement IEnumerable<T>:

public class PCB_Node<T> : IEnumerable<T> where T : PCB_Node<T>

Secondly, this could cause you problems:

get_iterator((T)this)

Although T is a PCB_Node<T>, this, being of type PCB_Node<T> is not necessarily a T, which would lead to a runtime exception in this example:

class DerivedNode : PCB_Node<DerivedNode> { }

var node = new PCB_Node<DerivedNode>();
var enumerator = node.GetEnumerator(); // InvalidCastException

If you want to offload the implementation of GetEnumerator to a static method, you would need to declare it like this:

public class PCB_Node<T> : IEnumerable<T> where T : PCB_Node<T>
{
    public IEnumerator<T> GetEnumerator() => get_iterator(this);

    public static IEnumerator<T> get_iterator(PCB_Node<T> node)
    {
        //...
    }
}

If get_iterator is declared in another class, you would need to reapply the constraint:

public class AnotherClass
{
    public static IEnumerator<T> get_iterator<T>(PCB_Node<T> node) where T : PCB_Node<T>
    {
        //...
    }
}

Then call like this:

public IEnumerator<T> GetEnumerator() => AnotherClass.get_iterator(this);

Upvotes: 1

JonasH
JonasH

Reputation: 36659

You probably want to have the following declaration:

public class PCB_Node<T> : IEnumerable<T> where T : PCB_Node<T>

I.e. Your PCB_Node is a IEnumerable, and that T has to be the same kind of PCB_Node

I'm not familiar with static classes in java , but you I would guess you want a regular class.

To implement the IEnumerable you can use a iterator block:

    public IEnumerator<T> GetEnumerator()
    {
        yield return this
        // add iteration logic
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

Personally I would consider separating the iterator from the class, since a tree can be iterated in several different ways. for example by using an extension method:

public static IEnumerable<T> DepthFirst<T>(this PCB_Node<T> root) where T : PCB_Node<T>
{
    yield return root;
    // add iteration logic
}

Upvotes: 0

Related Questions