Buthrakaur
Buthrakaur

Reputation: 1851

c# - cast generic class to its base non-generic class

I have following classes:

public abstract class CustomerBase
{
    public long CustomerNumber { get; set; }
    public string Name { get; set; }
}

public abstract class CustomerWithChildern<T> : CustomerBase
    where T: CustomerBase
{
    public IList<T> Childern { get; private set; }

    public CustomerWithChildern()
    {
        Childern = new List<T>();
    }
}

public class SalesOffice : CustomerWithChildern<NationalNegotiation>
{
}

The SalesOffice is just one of few classes which represent different levels of customer hierarchy. Now I need to walk through this hierarchy from some point (CustomerBase). I can't figure out how to implement without using reflection. I'd like to implement something like:

    public void WalkHierarchy(CustomerBase start)
    {
        Print(start.CustomerNumber);
        if (start is CustomerWithChildern<>)
        {
            foreach(ch in start.Childern)
            {
                WalkHierarchy(ch);
            }
        }
    }

Is there any chance I could get something like this working?


The solution based on suggested has-childern interface I implemented:

public interface ICustomerWithChildern
{
    IEnumerable ChildernEnum { get; }
}

public abstract class CustomerWithChildern<T> : CustomerBase, ICustomerWithChildern
    where T: CustomerBase
{
    public IEnumerable ChildernEnum { get { return Childern; } }

    public IList<T> Childern { get; private set; }

    public CustomerWithChildern()
    {
        Childern = new List<T>();
    }
}

    public void WalkHierarchy(CustomerBase start)
    {
        var x = start.CustomerNumber;
        var c = start as ICustomerWithChildern;
        if (c != null)
        {
            foreach(var ch in c.ChildernEnum)
            {
                WalkHierarchy((CustomerBase)ch);
            }
        }
    }

Upvotes: 7

Views: 10739

Answers (6)

Sunny Milenov
Sunny Milenov

Reputation: 22320

Try this:

if(start.GetType().GetGenericTypeDefinition() == typeof(CustomerWithChildern<>))

Upvotes: 3

x0n
x0n

Reputation: 52480

I think everyone hits this "issue" when first working with generic classes.

Your first problem is hinted at in your question phrasing: an open generic type is NOT the base class to a closed one. There is no OO relationship here, at all. The real base class is CustomerBase. An "open" generic type is like a half-completed class; specifying type arguments "closes" it, making it complete.

While you can do:

Type t = typeof(CustomerWithChildern<>)

the condition

typeof(CustomerWithChildern<>).IsAssignableFrom(CustomerWithChildern<Foo>)

will always be False.

-Oisin

Upvotes: 1

Mitchel Sellers
Mitchel Sellers

Reputation: 63136

I believe that you want to make the lookup for the determination of doing to the walk an interface.

So maybe add an "IWalkable" interface that exposes the information needed to do the walk, then you can create your method checking to see if the passed object implements the interface.

Upvotes: 2

Adam Robinson
Adam Robinson

Reputation: 185703

Explicitly with that method, no. However you can achieve the same functionality with an interface. In fact, you could just have your generic class implement IEnumerable. It's also worth noting that your class should also have "where T : CustomerBase" in order to ensure type safety.

Upvotes: 0

John Saunders
John Saunders

Reputation: 161831

You could move the WalkHierarchy method to the base class and make it virtual. The base class implementation would only process the current node. For the CustomerWithChildern<T> class, the override would do an actual walk.

Upvotes: 7

Reed Copsey
Reed Copsey

Reputation: 564851

"Is" and "As" only work on fully qualified generic types.

See this MSDN discussion for details including workarounds.

The most common workaround I've seen is to add an interface to the mix that your CustomerWithChildren could implement, and check for that interface.

Upvotes: 2

Related Questions