C#中同一列表中的逆变量或不变量接口

时间:2018-03-01 08:03:45

标签: c# list covariance contravariance invariance

我遇到了关于界面协方差和逆变的问题。我有两个通用接口:

public interface IConfigConsumer<T> where T : IConfiguration
{
    void Load(T configuration);
}

public interface IConfigProvider<out T> where T : IConfiguration
{
    T Configuration { get; }
}

IConfiguration只是一个空接口(标记)。还有第三个界面:

public interface IConfigurable<T> : IConfigConsumer<T>, IConfigProvider<T>
    where T : IConfiguration
{
    void Reset();
}

我想有一个包含所有IConfigurable实现的列表(不管T的具体类型如何)。 由于IConfigProvider是协变的,我可以有一个IConfigProviders列表,但IConfigConsumer是不变的,所以我不能有这样的List:

var consumers = new List<IConfigConsumer<IConfiguration>>();

最好的是列出IConfigurable<IConfiguration>,因为我需要在两个接口中定义的功能。

我无法找到办法做到这一点。

解决方法可能是删除IConfigConsumer接口中的type参数并定义Load方法,如下所示:

void Load(IConfiguration configuration)

但那会伤害&#34;类型安全有点,因为我可以将类型ConfigA加载到ConfigConsumer中,它需要ConfigB,并且它只会在运行时抛出异常,当我尝试在Load方法中将其强制转换为ConfigB时。

以下是我的完整示例代码:

public interface IConfiguration
{
}

public interface IConfigurable<T> : IConfigConsumer<T>, IConfigProvider<T>
    where T : IConfiguration
{
    void Reset();
}

public interface IConfigConsumer<T> where T : IConfiguration
{
    void Load(T configuration);
}

public interface IConfigProvider<out T> where T : IConfiguration
{
    T Configuration { get; }
}

public abstract class ConfigBase : IConfiguration { }

public class TimeSynchronizationConfig : ConfigBase, ICloneable
{
    public static string[] DefaultNtpServers = new string[] { "0.pool.ntp.org", "time1.google.com" };

    public string NTPServer1 { get; set; } = DefaultNtpServers[0];
    public string NTPServer2 { get; set; } = DefaultNtpServers[1];

    public object Clone()
    {
        return new TimeSynchronizationConfig
        {
            NTPServer1 = NTPServer1,
            NTPServer2 = NTPServer2
        };
    }
}

public class DataPruningConfig : ConfigBase, ICloneable
{
    public const int DefaultPruningThresholdHours = 72;
    public int PruningThresholdHours { get; set; }

    public DataPruningConfig()
    {
        PruningThresholdHours = DefaultPruningThresholdHours;
    }

    public DataPruningConfig(int pruningThresholdHours)
    {
        PruningThresholdHours = pruningThresholdHours;
    }

    public object Clone()
    {
        return new DataPruningConfig(PruningThresholdHours);
    }
}

public class A : IConfigurable<TimeSynchronizationConfig>
{
    public TimeSynchronizationConfig Configuration => new TimeSynchronizationConfig();

    public void Load(TimeSynchronizationConfig configuration)
    {
        throw new NotImplementedException();
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }
}

public class B : IConfigurable<DataPruningConfig>
{
    public DataPruningConfig Configuration => new DataPruningConfig();

    public void Load(DataPruningConfig configuration)
    {
        throw new NotImplementedException();
    }

    public void Reset()
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var configurables = new List<IConfigurable<IConfiguration>>();
        var a = new A();
        var b = new B();

        configurables.Add(a);
        configurables.Add(b);

        ProcessConfigurables(configurables);
    }

    static void ProcessConfigurables(IEnumerable<IConfigurable<IConfiguration>> configurables)
    {
        foreach (var c in configurables)
        {

        }
    }
}

我开始怀疑我想要的是什么。你有什么主意吗? 提前感谢您的帮助!

0 个答案:

没有答案