views:

171

answers:

3

Hi! I have confusing situation.

Base Generic Type and successor

public abstract class BaseType<TEntity> : where TEntity : BaseType<TEntity>
public class AnyType : BaseType<AnyType>

It looks like a generic loop)))

I need Method like

public void Method<T>(T data)
{
if(typeof(T).IsSubclassOf(BaseType<????>))
 convert data to BaseType<???> and exec BaseType<>'s method
else
//Do that
}

In generic Method i need to defines that T is BaseType and exec method on it. How can I do that????

+1  A: 

You can use reflection and work your way up the hierarchy using Type.BaseType. Note that depending on the exact concrete class, the base type could still be an open generic type, e.g.

class Foo<T> : BaseType<T>

You can use Type.IsGenericTypeDefinition and Type.GetGenericTypeDefinition to try to work your way to BaseType<>. Basically you want to find out whether any class in the inheritance hierarchy has a generic type definition which is typeof(BaseType<>). Just be glad you're not dealing with interfaces, which make the whole thing even harder :)

Jon Skeet
10x for replies! But I need additional feature. public void Method<T>(T data) Exec BaseType<> method on Data... I my use Reflection, but I prefer type conversion to BaseType<>. Is It possible?
sh1ng
@sh1ng: It's not really clear what you mean. Perhaps you should use `Method<TBase, TItem>`(TBase value) where TBase : BaseType<TItem>`?
Jon Skeet
I can't add type constrain to generic method...If data(param) is BaseType<SuccessorType> then call ((BaseType<T>)data).Method() else another action....The problem in ((BaseType<T>)data)The type 'T' cannot be used as type parameter 'TEntity' in the generic type or method 'BaseType<TEntity>'. There is no boxing conversion or type parameter conversion from 'T' to 'BaseType<T>'Actually I need convert T to 'B<T> : where T : B<T>'
sh1ng
@sh1ng: Consider having a nongeneric base type, so that say `BaseType<T> : BaseType` - and put any methods which don't depend on `T` into that. It can make life a lot easier.
Jon Skeet
I know, but it's artifact....If I can't create any hook I will use Reflection method call.But now I'm thinking about the solution.
sh1ng
+1  A: 

You can use the following code:

static bool IsBaseType<T>()
{
    var t = typeof(T);

    do
    {
        if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(BaseType<>))
        {
            return true;
        }

        t = t.BaseType;
    }
    while (t != null);

    return false;
}
Steven
10x for replies! But I need additional feature. public void Method<T>(T data) Exec BaseType<> method on Data... I my use Reflection, but I prefer type conversion to BaseType<>. Is It possible?
sh1ng
A: 

A common pattern in this case is to have a non-generic base type of the generic base type. If your method doesn't involve the type parameter, then you're done. If it does, you could add a non-generic method that does a typecast, similar to Object.Equals:

public abstract class ReallyBaseType
{
    public abstract void SomeMethod();
    public abstract void SomeMethodWithParameter(object o);
}

public abstract class BaseType<TEntity> : ReallyBaseType
    where TEntity : BaseType<TEntity>
{
    public override void SomeMethodWithParameter(object o)
    {
        SomeMethodWithParameter((TEntity)o);
    }

    public abstract void SomeMethodWithParameter(TEntity entity);
}

public class AnyType : BaseType<AnyType>
{
    public override void SomeMethod() { }

    public override void SomeMethodWithParameter(AnyType entity) { }
}

Then, you can just check the actual type of data:

public void Method<T>(T data)
{
    if (data is ReallyBaseType)
    {
        ((ReallyBaseType)(object)data).SomeMethod();
    }
}

EDIT: I think you're stuck using reflection, then. If you want to be able to write code against the concrete type, you could create a generic method and invoke it using reflection:

public class TestClass
{
    private static MethodInfo innerMethodDefinition =
        typeof(TestClass).GetMethod("InnerMethod");

    public void Method(object data)
    {
        var t = data.GetType();
        while (t != null &&
            !(t.IsGenericType &&
            t.GetGenericTypeDefinition() == typeof(BaseType<>)))
        {
            t = t.BaseType;
        }
        if (t != null &&
            t.GetGenericArguments()[0].IsAssignableFrom(data.GetType()))
        {
            innerMethodDefinition.MakeGenericMethod(
                t.GetGenericArguments()[0]).Invoke(this, new object[] { data });
        }
    }


    public void InnerMethod<TEntity>(TEntity data)
        where TEntity : BaseType<TEntity>
    {
        // Here you have the object with the correct type
    }
}
Quartermeister
I know that, but It's imposable in the current project(((
sh1ng