C #: тип конструкции с ограниченным полузакрытыми реализациями открытого универсального интерфейса через открытый универсальный метод / класс - PullRequest
0 голосов
/ 19 мая 2019

Я пытаюсь создать экземпляры открытого универсального интерфейса репозитория, посредством чего реализации налагают более строгие ограничения типов, чем интерфейс.Каждой реализации интерфейса репозитория требуется конкретная реализация универсального типа для обработки определенных методов / операций на основе свойств переданного типа (для краткости не показаны).

Вот исчерпывающий пример сценария:

public interface IRepository<T> where T : class
{
    //...
}

public class BaseRepository<T> : IRepository<T> where T : DbModel
{
    //...
}

public class SqlServerDbRepository<T> : BaseRepository<T> where T : SqlServerDbModel
{
    //...
}

public abstract class DbModel
{
    //...
}

// is further derived by other models
public class SqlServerDbModel : DbModel
{
    //...
}

public class User : SqlServerDbModel
{
}

// CLIENT CODE

public static IRepository<T> BuildRepository<T>()
    where T : class
{
    if (typeof(T) == typeof(SqlServerDbModel)) // "is" keyword will not work here (according to IDE, have not checked)
    {
        return new SqlServerDbRepository<T>(); // How can T be converted or accepted as an input of type "SqlServerDbModel" (the check already confirms it, so we know it should work)
    }
    else if (typeof(T) == typeof(DbModel))
    {
        return new BaseRepository<T>(); // How can T be converted or accepted as an input of type "DbModel" (the check already confirms it, so we know it should work)
    }
    //... else throw error or just return default...
}

// USAGE
public static void TestBuildRepository()
{
    var userRepository = BuildRepository<User>();
}

Сначала я попытался запустить сценарий через контейнер IOC (Castle Windsor на случай, если кому-то интересно), подумав, что он автоматически определит ограничения типов, однако это было невозможно (или, по крайней мере, нет).с тем, как он обрабатывает открытые дженерики и внедрение зависимостей).Я подумал, что мог бы использовать собственную фабрику для построения реализаций интерфейса.

Проблема в строках, соответствующих шаблону return new XYZRepository<T>();, из-за чего я не уверен, как заставить компилятор c # принять универсальный тип "Tmsgstr "передано ему, зная, что оно полностью удовлетворит ограничение типа.Я уверен, что это можно сделать с помощью размышлений, но я нашел только информацию о том, как создавать методы и свойства, а не общие классы.Как этого достичь?

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

Ответы [ 2 ]

1 голос
/ 19 мая 2019

Я думаю, вы ищете что-то вроде этого:

    public static IRepository<T> BuildRepository<T>() where T : class
    {
        if (typeof(T) == typeof(SqlServerDbModel))
        {
            return (IRepository<T>)new SqlServerDbRepository<SqlServerDbModel>();
        }

        if (typeof(T) == typeof(DbModel))
        {
            return (IRepository<T>)new BaseRepository<DbModel>();
        }

        // ...
    }
0 голосов
/ 19 мая 2019

Это помогает выписать проблему, и, как оказалось, это оказалось проще, чем я первоначально ожидал. Ответ @ CRAGIN дал мне последний недостающий фрагмент (поскольку ... о, да, мы можем привести к интерфейсам в C #).

На случай, если кто-нибудь из будущего споткнется ...

public static IRepository<T> BuildRepository<T>(params object[] constructor_arguments)
    where T : class
{
    if (typeof(T) == typeof(SqlServerDbModel))
    {
        return (IRepository<T>)Activator.CreateInstance(typeof(SqlServerDbRepository<>).MakeGenericType(typeof(T)), constructor_arguments);
    }
    else if (typeof(T) == typeof(DbModel))
    {
        return (IRepository<T>)Activator.CreateInstance(typeof(BaseRepository<>).MakeGenericType(typeof(T)), constructor_arguments);
    }
    //... else throw error or just return default...
}

Мне нужно было использовать API Activator.CreateInstance, чтобы создать объект, а затем просто вернуть его к правильному типу. Хотелось бы, чтобы в Виндзорском замке был способ сделать это "изначально", не прибегая к индивидуальной фабрике / отражению.

...