2

类似于这个问题:我如何需要一个方法参数来实现多个接口? 我想要一个方法参数来实现几个接口。

接口应该可以以任意方式组合,我不想为每个有效组合创建一个接口。

想一个文件。有可能:

  1. 可读 =>IReadable
  2. 可写 =>IWriteable
  3. 档案=>IArchive
  4. 自动生成 =>IGenerated

...

如果我想表达一个参数需要是一个可写的、生成的存档,我不想生成IWritableGeneratedArchive,因为组合太多,我想将它与一些我无法修改的现有类一起使用。

伪代码:

void WriteTo( IWritable + IGenerated + IArchive file)
{
   //...
}
4

5 回答 5

8

我在这里找到的解决方案:如何需要方法参数来实现多个接口?针对 C# 进行了调整。

学分去迈克尔迈尔斯

internal interface IF1
{
    void M1();
}

internal interface IF2
{
    void M2();
}

internal class ClassImplementingIF1IF2 : IF1, IF2
{

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

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

}

internal static class Test
{

    public static void doIT<T>(T t) where T:IF1,IF2
    {
        t.M1();
        t.M2();
    }

    public static void test()
    {
        var c = new ClassImplementingIF1IF2();
        doIT(c);
    }
}
于 2012-10-25T13:11:53.913 回答
3

一个通用的 + 约束可能吗?

void WriteTo<T>( T file) where T : IWritable,IGenerated,IArchive
{
   //...
}
于 2012-10-25T13:19:40.657 回答
2

使用通用约束:

void WriteTo<T>(T file) where T: IWritable, IGenerated, IArchive
{
   //...
}

请参阅类型参数的约束(C# 编程指南)

于 2012-10-25T13:20:03.327 回答
0

我不想生成 IWritableGeneratedArchive 因为组合太多

怎么组合太多了?无论有多少潜在的组合,您只需要为实际用作方法参数的组合创建一个组合接口,然后无论如何都要写出来。换句话说,实际上并没有那么多工作。

我想将它与一些我无法修改的现有类一起使用。

可以将 IWritableGeneratedArchive 类型传递给只需要 IArchive 或 IWritable 的东西。这仍然适用于您已经拥有的任何其他东西。


但是既然你已经决定反对这个,而且看起来你已经在这个架构上投入了很多,我想知道你是否看过Code Contracts。他们看起来可能会做你需要的事情。

于 2012-10-25T13:19:22.633 回答
0

这个解决方案试图将 supercat 的想法与存储这样的“多接口”对象结合起来。

我通过将它们存储在一个Holder公开对象的指定接口的类中来做到这一点。

Holder对象可以被存储并且是预期的参数。缺点是您必须创建第一个,并且类型参数Holder的顺序很重要。Holder

从好的方面来说,您还可以动态创建Holders,当然还可以存储“多接口”对象。

启用这些holder.Get<T>()方法(比 holder.t1 更好)会很好,但它不会编译。 也许有人知道如何解决它?我认为它需要添加约束T1不是T2,反之亦然。这个与 C# 泛型相关的接缝*没有*实现某些东西,他们没有找到解决方案。

internal interface IF1
{
    void M1();
}

internal interface IF1_extension : IF1
{
}

internal interface IF2
{
    void M2();
}

internal class ClassImplementingIF1IF2 : IF1_extension, IF2
{

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

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

}

internal interface Getter<T> where T : class
{
    T Get();
}

internal class Holder<T1, T2> //: Getter<T1>, Getter<T2> // not possible since T1 and T2 may be the same => won't compile!
    where T1 : class
    where T2 : class
{
    private Holder(T1 t1, T2 t2)
    {
        Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
        Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
        this.t1 = t1;
        this.t2 = t2;
    }

    public static Holder<T1, T2> CreateFrom<T>(T t) where T : T1, T2
    {
        return new Holder<T1, T2>(t, t);
    }
    public static Holder<T1, T2> CreateDynamicallyFrom(object t)
    {
        return new Holder<T1, T2>(t as T1, t as T2);
    }

    public readonly T1 t1;
    public readonly T2 t2;

    //T1 Getter<T1>.Get()
    //{
    //    return t1;
    //}
    //T2 Getter<T2>.Get()
    //{
    //    return t2;
    //}
}

internal class Holder<T1, T2, T3>  // Holder<T1,T2,T3,T4> etc. are defined in a similar way
    where T1 : class
    where T2 : class
    where T3 : class
{
    private Holder(T1 t1, T2 t2, T3 t3)
    {
        Debug.Assert(t1 != null, "Argument is no " + typeof(T1).Name);
        Debug.Assert(t2 != null, "Argument is no " + typeof(T2).Name);
        Debug.Assert(t3 != null, "Argument is no " + typeof(T3).Name);
        this.t1 = t1;
        this.t2 = t2;
        this.t3 = t3;
    }

    public static Holder<T1, T2,T3> CreateFrom<T>(T t) where T : T1, T2, T3
    {
        return new Holder<T1, T2, T3>(t, t, t);
    }
    public static Holder<T1, T2, T3> CreateDynamicallyFrom(object t)
    {
        return new Holder<T1, T2, T3>(t as T1, t as T2, t as T3);
    }

    public readonly T1 t1;
    public readonly T2 t2;
    public readonly T3 t3;

}


internal static class Test
{

    public static void doIt<T>(T t) where T : IF1, IF2
    {
        t.M1();
        t.M2();
    }

    public static void doIt(Holder<IF1, IF2> t) // Interfaces should be mentioned in alpahbetical order since Holder<IF1,IF2> != Holder<IF2,IF1>
    {
        t.t1.M1();
        t.t2.M2();
    }


    public static void doIt_extended<T1, T2>(Holder<T1, T2> t) // handles conversions from Holder<T1,T2> to Holder<T1 or base of T1, T2 or base of T2>
        where T1 : class, IF1
        where T2 : class, IF2
    {
        t.t1.M1();
        t.t2.M2();
    }

    public static void test()
    {
        var c = new ClassImplementingIF1IF2();
        doIt(c);
        var c_holder = Holder<IF1, IF2>.CreateFrom(c);
        doIt(c_holder);

        var another_c_holder = Holder<IF1_extension, IF2>.CreateFrom(c);
        doIt_extended(another_c_holder);


        object diguised_c = c;
        var disguised_c_holder = Holder<IF1, IF2>.CreateDynamicallyFrom(diguised_c);
        doIt(disguised_c_holder);

    }
}
于 2012-10-26T10:40:18.840 回答