Преобразование универсального типа

У меня серьезные проблемы с дизайном из-за проблем с обобщениями. Возможно у кого-то есть предложения.

РЕДАКТИРОВАТЬ: Итак, я знаю, что обычно этого не делают, но я полностью изменил свой примерный код, потому что понял, что исходный псевдокод на самом деле не объясняет мою проблему. Следующий код намного больше напоминает реальный пример, с которым я имею дело. Я надеюсь, что моя проблема будет яснее от этого. Я заранее прошу прощения, что это немного длинно, но по моему опыту, проблемы с дженериками обычно проявляются, когда вы пытаетесь построить более сложную структуру. Итак:

class Program
    {
        static void Main(string[] args)
        {
            IConnector<IService> connector = ConnectorBuilderFactory.NewBuilder<IService>("someEndpoint").MakeReliable().GetConnector();
            connector.Connect();
        }
    }

    public interface IService : IConnectionMaintainable
    {
        void DoSomething();
    }

    public interface IConnectionMaintainable
    {
        DateTime GetServerTime();
    }

    public interface IConnector<T>
    {
        T Channel { get; }
        void Connect();
        void Disconnect();
    }

    public interface IConnectorBuilder<T>
    {
        IConnector<T> GetConnector();
        IConnectorBuilder<T> MakeReliable();
        // ...more connector-configuration methods
    }

    public class ChannelWatchDog<T> where T : IConnectionMaintainable
    {
        private IConnector<T> connector;

        public ChannelWatchDog(IConnector<T> connector /*various other parameters*/)
        {
            this.connector = connector;
        }

        // ...methods that use connector's Connect, Disconnect, and GetServerTime methods
    }

    public class Connector<T> : IConnector<T>
    {
        private T channel;

        public Connector(string endpoint)
        {
            // ...build channel
        }

        public T Channel
        {
            get { return channel; }
        }

        public void Connect()
        {
            // ...connect to server
        }

        public void Disconnect()
        {
            // ...disconnect from server
        }
    }

    public class ConnectorBuilder<T> : IConnectorBuilder<T>
    {
        private string endpoint;

        public ConnectorBuilder(string endpoint)
        {
            this.endpoint = endpoint;
        }

        public IConnector<T> GetConnector()
        {
            Connector<T> connector = new Connector<T>(endpoint);

            // If reliability was requested, build the ChannelWatchDog: Following line does not compile:
            // ChannelWatchDog<T> watchDog = new ChannelWatchDog<T>(connector);

            return connector;
        }

        public IConnectorBuilder<T> MakeReliable()
        {
            // save various parameters required to build the ChannelWatchDog
            return this;
        }
    }

    public static class ConnectorBuilderFactory
    {
        public static IConnectorBuilder<T> NewBuilder<T>(string endpoint)
        {
            return new ConnectorBuilder<T>(endpoint);
        }
    }

Итак, во-первых, если вы найдете метод GetConnector в классе ConnectorBuilder, вы увидите закомментированную строку кода, которая не компилируется, если она не закомментирована. Эта строчка - суть моей проблемы. Проблема может быть очевидна из кода, но я все равно попытаюсь объяснить ее, если это не так:

  1. У меня есть внутренний класс (ChannelWatchDog), которому нужен IConnector. Но не только любой IConnector, IConnector, потому что, кроме неуниверсальных методов IConnector, ему также нужен метод GetServerTime из интерфейса IConnectionMaintainable.

  2. Чтобы упростить построение соединителей, Я надеялся реализовать построитель с использованием шаблона Expression Builder (интерфейс IConnectionBuilder). Однако я хочу иметь возможность создавать любой IConnector, а не только IConnector . Поэтому я не могу ограничить T в IConnectorBuilder так же, как я ограничиваю его для ChannelWatchDog. Из-за отсутствия этого ограничения у меня нет возможности построить его при вызове GetConnector. Добавление ограничения к методу MakeReliable не помогает.

Итак, по сути, причина, по которой я разместил этот вопрос, заключалась в том, что я хотел сделать что-то, что очевидно невозможно. Я хотел, чтобы классы ChannelWatchDog и ConnectorBuilder выглядели примерно так:

public class ChannelWatchDog
    {
        private IConnector<IConnectionMaintainable> connector;

        public ChannelWatchDog(IConnector<IConnectionMaintainable> connector /*various other parameters*/)
        {
            this.connector = connector;
        }

        // ...methods that use connector's Connect, Disconnect, and GetServerTime methods
    }

    public class ConnectorBuilder<T> : IConnectorBuilder<T>
    {
        private string endpoint;

        public ConnectorBuilder(string endpoint)
        {
            this.endpoint = endpoint;
        }

        public IConnector<T> GetConnector()
        {
            Connector<T> connector = new Connector<T>(endpoint);

            // If reliability was requested, build the ChannelWatchDog: Following line does not compile:
            ChannelWatchDog watchDog = new ChannelWatchDog((IConnector<IConnectionMaintainable>)connector);

            return connector;
        }

        public IConnectorBuilder<TReliable> MakeReliable<TReliable>() where TReliable : T, IConnectionMaintainable
        {
            // save various parameters required to build the ChannelWatchDog
            return (IConnectorBuilder<TReliable>)this;
        }
    }

Но приведение к IConnector не удается во время выполнения.

Так что это было намного дольше, чем я предполагал изначально. Если ты' Приветствуются любые идеи, включая реструктуризацию кода.

Кстати, так и не найдя решения этой проблемы, я создал различные ConnectorBuilder (в данном случае ReliableConnectorBuilder) и различные фабричные методы на фабрике. Но мне не очень нравится это решение.

РЕДАКТИРОВАТЬ: Просто чтобы уточнить и повторить: я не могу ограничить IConnector или ConnectionBuilder, потому что они должны поддерживать случаи, в которых интерфейс IConnectionMaintainable не реализован.

5
задан joniba 15 December 2010 в 14:01
поделиться