开发者

C# generic How to define that T is Base<Tp> : where Tp : Base<Tp> and Call Base<Tp> method

开发者 https://www.devze.com 2023-01-08 22:15 出处:网络
I have confusing situation. Base Generic Type and successor public abstract class BaseType<TEntity> : where TEntity : BaseType<TEntity>

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????


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 :)


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;
}


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
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消