Проверка C# для реализации универсального интерфейса

Как проверить, что класс каким-либо образом реализует универсальный интерфейс?

У меня есть следующее:

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

Есть ли способ использовать этот интерфейс, чтобы проверить, что параметр реализует универсальный интерфейс без предоставления T? Передача базового класса не совпадает, и использование класса SomeQueryDto победит точку

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

Я мог бы изменить интерфейс для реализации другого неуниверсального интерфейса и проверить это, но тогда классы могли бы просто использовать это и не иметь универсального интерфейса вообще:

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
}

2 ответа

Решение

Вы хотели что-то вроде этого:

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

}

но без подачи Т1?

Вы можете упростить это в зависимости от ваших потребностей: Вот полный пример кода того, чего, я думаю, вы пытаетесь достичь. В AnotherClass есть две разные сигнатуры методов, которые вы можете использовать.

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

Если я вас правильно понял, вы пытаетесь проверить, реализует ли класс универсальный интерфейс с определенным универсальным типом. Предполагая, что у вас есть экземпляр этого класса, вы можете сделать это следующим образом:

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

Кроме того, если у вас нет экземпляра и вы хотите выполнить проверку класса, просто замените instnace.GetType() с typeof(SomeDto),

Другие вопросы по тегам