通用类型转换

时间:2010-12-01 09:05:16

标签: .net generics

由于泛型问题,我遇到了一些严重的设计问题。也许有人有一些建议。

编辑:所以,我知道这通常不会完成,但我已经完全改变了我的示例代码,因为我已经意识到原始的伪代码并没有真正解释我的问题。以下代码更接近于我正在处理的真实示例。我希望我的问题能更明确。我向前道歉它有点冗长,但根据我的经验,当你试图建立一个更复杂的结构时,通常会出现泛型问题。所以:

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

因此,首先,如果在ConnectorBuilder类中找到GetConnector方法,您将看到注释的代码行,如果取消注释则不会编译。这一行是我的问题的本质。问题可能从代码中显而易见,但无论如何我都会尝试解释它:

  1. 我有一个需要IConnector的内部类(ChannelWatchDog)。但不仅仅是IConnector,IConnector,因为除了非通用的IConnector方法之外,它还需要来自IConnectionMaintainable接口的GetServerTime方法。

  2. 为了简化连接器的构造,我希望使用Expression Builder模式(IConnectionBuilder接口)实现构建器。但是,我希望能够构建任何IConnector,而不仅仅是IConnector&lt; IConnectionMaintainable&gt;。因此,我不能以与限制它为ChannelWatchDog相同的方式约束IConnectorBuilder中的T.缺少这个约束,我无法在调用GetConnector时构建它。将约束添加到MakeReliable方法没有帮助。

  3. 所以,基本上我发布这个问题的原因是我想做一些显然不可能的事情。我希望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的演员阵容在运行时失败了。

    所以这比我原先打算的要长得多。如果你已经阅读了这么远,那么你已经得到了我的谢意:) 欢迎任何想法,包括重组代码。

    BTW,我自己没有找到解决方案,我在工厂中创建了不同的ConnectorBuilders(在本例中为ReliableConnectorBuilder)和不同的工厂方法。但我不太喜欢这个解决方案。

    编辑:只是澄清并重申:我不能约束IConnector和ConnectionBuilder,因为这些需要支持未实现IConnectionMaintainable接口的情况。

6 个答案:

答案 0 :(得分:5)

接口代码?

GenericClass<IFoo> wrapper = new GenericClass<IFoo>(new FooImplementor());
Acceptor acceptor = new Acceptor(wrapper);

答案 1 :(得分:1)

您对GenericClass的要求称为Covarianz。有关详情,请观看this。我应该去找马克的答案,但如果这不是你想要的,那就试试吧:

class GenericClass<out T> { ... }

答案 2 :(得分:1)

可以使用反射来允许将Connector<T>转换为Connector<IConnectionMaintainable>,但我不确定这会对性能有多大,并且它需要能够克隆Connector<T>

public class Connector<T> : IConnector<T>
{
    // ...
    private Connector()
    {
    }
    // ...
    public static explicit operator Connector<IConnectionMaintainable>(Connector<T> other)
    {
        Connector<IConnectionMaintainable> connector = null;

        Type p = typeof(T);
        if (p.GetInterfaces().Contains(typeof(IConnectionMaintainable)))
        {
            connector = new Connector<IConnectionMaintainable>();
            connector.channel = other.channel as IConnectionMaintainable;
        }
        else
        {
            throw new InvalidCastException();
        }

        return connector;
    }
}

public class ConnectorBuilder<T> : IConnectorBuilder<T>
{
    // ...
    public IConnector<T> GetConnector()
    {
        Connector<T> connector = new Connector<T>(endpoint);

        // If reliability was requested, build the ChannelWatchDog:
        try 
        {
            Connector<IConnectionMaintainable> temp = (Connector<IConnectionMaintainable>)connector;
            ChannelWatchDog<IConnectionMaintainable> watchDog = new ChannelWatchDog<IConnectionMaintainable>(temp);
        }
        catch (InvalidCastException)
        {
            throw new ArgumentException("Trying to make reliable when not possible");
        }

        return connector;
    }
    // ...
}

答案 3 :(得分:0)

您可以GenericClass<T>实现/扩展非泛型接口/基类,就像.NET中的列表和枚举一样。实际的泛型类型可以是返回Type对象的抽象方法/属性,并在泛型类中实现。

答案 4 :(得分:0)

如果这行未编译是主要问题:

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

然后我认为它应该是

ChannelWatchDog watchDog = new ChannelWatchDog(connector);

除了你的运行时强制转换失败,我相信因为IConnector需要被约束:

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

这是来自时尚,希望提供见解或提示。约束根据linqpad进行编译。

它还会导致级联约束要求,所以这里是编译的其余代码:

void Main()
{

}

// Define other methods and classes here
  public interface IConnectionMaintainable
{
    DateTime GetServerTime();
}

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

 public interface IConnectorBuilder<T> where T:IConnectionMaintainable
{
    IConnector<T> GetConnector();
    IConnectorBuilder<T> MakeReliable();
    // ...more connector-configuration methods
}
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> where T:IConnectionMaintainable
{
    private string endpoint;

    public ConnectorBuilder(string endpoint)
    {
        this.endpoint = endpoint;
    }
    public IConnectorBuilder<T> MakeReliable()
    {
        // save various parameters required to build the ChannelWatchDog
        return this;
    }
    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;
    }
}

 public class Connector<T> : IConnector<T> where T:IConnectionMaintainable
{
    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
    }
}

答案 5 :(得分:0)

你应该在ConnectorBuilder类中使用泛型参数T来实现IConnectionMaintainable接口。原因是通用类型的ChannelWatchDog需要它。泛型T对于ChannelWatchDog的泛型类型参数不够严格。