Search code examples
c#genericsinterfacegeneric-interface

C# Check for implementation of generic interface


How do I check that a class implements a generic interface in any way?

I have the following:

public class SomeQueryObject : IQueryObject<SomeQueryDto>
{
    public SomeQueryDto query { get; set; } = new SomeQueryDto();
}

public class SomeQueryDto : BaseQueryDto
{
    // some properties
}

public class BaseQueryDto
{
    // some properties
}


public interface IQueryObject<T> where T : BaseQueryDto
{
    T query { get; set; }
}

Is there a way to use this interface to check that a parameter implements the generic interface without supplying T? Passing the base class doesn't match, and using the SomeQueryDto class would defeat the point

private static string BuildQueryObjectString<T>(T dto) 
        where T : IQueryObject<?>
{ 
     //use query field in method body
    dto.query= foo;
}

I could change the interface to implement another non generic interface and check that but then classes could just use this and not have the generic interface at all:

public interface IQueryObject<T> : IQueryObject where T : BaseQueryDto
{
    T query { get; set; }
}

public interface IQueryObject { }

public class SomeQueryObject : IQueryObject
{
    // no query field
}

private static string BuildQueryObjectString<T>(T dto) 
        where T : IQueryObject // kind of pointless, the above class would pass this check but doesn't implement the field
{ 
     //method body, no access to query field
    dto.query= foo; // error
}

Solution

  • Did you want something like this:

    public string SomeMethod<T, T1>(T obj) where T : IGenericInterface<T1> where T1 : BaseClass
    {
    
    }
    

    but without supplying T1?

    You can simplify it depending on you needs: Here is a the full code example of what I think you are trying to achieve. In AnotherClass there are two different method signatures that you can use.

    public class BaseClass
    {
        public virtual string Str { get; set; } = "base";
    }
    
    public class DerivedClass : BaseClass
    {
        public override string Str { get; set; } = "derived";
    }
    
    public class TestingClass
    {
        public TestingClass()
        {
            AnotherClass a = new AnotherClass();
    
            Console.WriteLine(a.SomeMethod<GenericObjClass<BaseClass>, BaseClass>(new GenericObjClass<BaseClass>(){ Query = new BaseClass()}));
            Console.WriteLine(a.SomeMethod<GenericObjClass<DerivedClass>, DerivedClass>(new GenericObjClass<DerivedClass>() { Query = new DerivedClass() }));
    
            Console.WriteLine(a.SomeMethod(new GenericObjClass<BaseClass>() { Query = new BaseClass() }));
            Console.WriteLine(a.SomeMethod(new GenericObjClass<BaseClass>() { Query = new DerivedClass() }));
        }
    }
    
    public class AnotherClass
    {
        public string SomeMethod<T>(T obj) where T : IGenericObj<BaseClass>
        {
            return obj.Query.Str;
        }
    
        public string SomeMethod<T, T2>(T obj) where T : IGenericObj<T2> where T2 : BaseClass
        {
            return obj.Query.Str;
        }
    }
    
    public class GenericObjClass<T> : IGenericObj<T> where T : BaseClass
    {
        public T Query { get; set; }
    }
    
    
    public interface IGenericObj<T> where T : BaseClass
    {
        T Query { get; set; }
    }