2

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
}
lanky393
  • 292
  • 4
  • 12

2 Answers2

1

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; }
}
Scrobi
  • 1,215
  • 10
  • 13
  • Yes, that's what I want, To be honest I'll settle for passing in both, like you've suggested, Just thought it could be neater :) – lanky393 Apr 21 '17 at 10:32
0

If I understood you correctly, what are you trying to do is to check if class implements generic interface with particular generic type. Assuming you have an instance of that class, you are able to do that in this way:

class Dto
{
    // definition
}

interface ISome<T>
{
    // definition
}

class SomeDto: ISome<Dto>
{
    // definition   
}

...
var instance = new SomeDto();

foreach(var type in instance.GetType().GetInterfaces()) {
    if(type.IsGenericType
        && type.GetGenericTypeDefinition() == typeof(ISome<>)
        && type.GetGenericArguments()[0] == typeof(Dto)) {
        // success
    }
}

Also, if you have no instance and want to make class check, simply replace instnace.GetType() with typeof(SomeDto).

Vladyslav
  • 786
  • 4
  • 19
  • I don't want to check, I want have a method signature that can take any type of ISome<>. Thanks – lanky393 Apr 21 '17 at 10:21
  • So let's clear it out: you have class that implements `ISome` and want to have method within it that accepts param of type `ISome`? – Vladyslav Apr 21 '17 at 10:24