繁体   English   中英

如何在一个接口中两次使用具有不同模板参数的相同接口?

[英]How to use same interface two times with diferrent template parameters, in an interface?

我想通过这个例子会更清楚。 我们希望在处理器类中看到两个具有不同参数的方法。 “ int处理(int值);” “双重处理(双重价值);”

但是编译器对IRoot说:'Generics.IRoot'不能同时实现'Generics.IProcess'和'Generics.IProcess',因为它们可能会为某些类型参数替换统一。

public class Processor : IRoot<int, double, int, double>
{
    // Here we want 2 methods
    public int Process(int item) { }
    public double Process(double item) { }
}

public interface IProcess<TResult, TItem>
{
    TResult Process(TItem item);
}

public interface IRoot<TR1, TR2, TItem1, TItem2> :
    IProcess<TR1, TItem1>,
    IProcess<TR2, TItem2>
{

}

这是我的解决方案。 它基于使用差异化的功能,因此您可以清楚了解所需的接口。 您必须添加否则未使用的参数,但这就是告诉您想要哪个参数的原因。

public interface First { }
public interface Second { }

public class Processor : IRoot<int, double, int, double>
{
    // Here we want 2 methods
    public int Process ( int item ) { System.Console.WriteLine ( "int Process" ); return item + 1; }
    public double Process ( double item ) { System.Console.WriteLine ( "double Process" ); return item + 10.748; }
}

public class TestProcessor : IRoot<int, int, int, int>
{
    int IProcessWithDifferentiator<int, int, First>.Process ( int item )
    {
        System.Console.WriteLine ( "int Process" ); return item + 1;
    }
    int IProcessWithDifferentiator<int, int, Second>.Process ( int item )
    {
        System.Console.WriteLine ( "int Process" ); return item + 100302;
    }
}

public interface IProcessWithDifferentiator<TResult, TItem, TDiff>
{
    TResult Process ( TItem item );
}

public interface IRoot<TR1, TR2, TItem1, TItem2> :
    IProcessWithDifferentiator<TR1, TItem1, First>,
    IProcessWithDifferentiator<TR2, TItem2, Second>
{

}

class Program
{
    static void Main ( string [] args )
    {
        Processor p = new Processor ();
        IProcessWithDifferentiator<int, int, First> one = p;
        System.Console.WriteLine ( "one.Process(4) = " + one.Process ( 4 ) );
        IProcessWithDifferentiator<double, double, Second> two = p;
        System.Console.WriteLine ( "two.Process(5.5) = " + two.Process ( 5.5 ) );

        TestProcessor q = new TestProcessor ();
        IProcessWithDifferentiator<int, int, First> q1 = q;
        System.Console.WriteLine ( "q1.Process(4) = " + q1.Process ( 4 ) );
        IProcessWithDifferentiator<int, int, Second> q2 = q;
        System.Console.WriteLine ( "q2.Process(5) = " + q2.Process ( 5 ) );

        System.Console.ReadLine ();
    }
}

这是输出。

int Process
one.Process(4) = 5
double Process
two.Process(5.5) = 16.248
int Process
q1.Process(4) = 5
int Process
q2.Process(5) = 100307

即使您使用IRoot<int,int,int,int> ,这也将起作用IRoot<int,int,int,int>如上所述。 它知道(因为我们告诉了它)要使用哪个IDifferentiatedProcess。

(以防万一,我使用的是Visual Studio2012。)

因此,在发布对这个问题的第一个答案(#1)之后 ,我意识到一个人通常可能希望能够将值从微分接口转换为非微分接口。 换句话说,要执行以下操作

IProcessWithDifferentiator<TRes, TItem, TDiff> : IProcess<TRes, TItem>

但是我们不能,因为在使用该接口时会遇到相同的错误(类型可能会统一)。

我注意到OP没有特别要求这样做,但是可以看到这将是下一个逻辑场景。

因此,返回到绘图板,并为此提供一个丑陋的解决方案,即拥有一种方法来返回向下转换的类型以及支持这种方法构造的代理。 (唯一的缓解措施是,可以在某种程度上重用代理类,如下所示。)以下是此练习的结果。

public interface Second { }
public interface Third { }

public class Processor : IRoot<float, int, double, float, int, double>
{
    // Here we want 3 methods
    public float Process ( float item ) { System.Console.WriteLine ( "  ...float Process..." ); return (float) (item - 55.75); }
    public int Process ( int item ) { System.Console.WriteLine ( "  ...int Process..." ); return item + 1; }
    public double Process ( double item ) { System.Console.WriteLine ( "  ...double Process..." ); return item + 10.748; }

    IProcess<int, int> IProcessWithDifferentiator<int, int, Second>.ConvertToBase ()
    {
        return new TP_Proxy<int, int, Second> ( this );
    }

    IProcess<double, double> IProcessWithDifferentiator<double, double, Third>.ConvertToBase ()
    {
        return new TP_Proxy<double, double, Third> ( this );
    }
}

public class TestProcessor : IRoot<int, int, int, int, int, int>
{
    int IProcess<int, int>.Process ( int item )
    {
        System.Console.WriteLine ( "  ...int Process1..." ); return item - 11;
    }
    int IProcessWithDifferentiator<int, int, Second>.Process ( int item )
    {
        System.Console.WriteLine ( "  ...int Process2..." ); return item + 12;
    }
    int IProcessWithDifferentiator<int, int, Third>.Process ( int item )
    {
        System.Console.WriteLine ( "  ...int Process3..." ); return item + 100302;
    }

    IProcess<int, int> IProcessWithDifferentiator<int, int, Second>.ConvertToBase ()
    {
        return new TP_Proxy<int, int, Second> ( this );
    }

    IProcess<int, int> IProcessWithDifferentiator<int, int, Third>.ConvertToBase ()
    {
        return new TP_Proxy<int, int, Third> ( this );
    }
}

public interface IProcess<TResult, TItem>
{
    TResult Process ( TItem item );
}

public interface IProcessWithDifferentiator<TResult, TItem, TDiff> // would love to ": IProcess<TResult, TItem>" here but won't work above
{
    TResult Process ( TItem item ); // replicated method from IProcess... yuck(!)
    IProcess<TResult, TItem> ConvertToBase ();
}

// Having a proxy sucks.  But at least this proxy is shared among multiple classes implementing the IProcess concept.
class TP_Proxy<TResult, TItem, TDiff> : IProcess<TResult, TItem>
{
    public TP_Proxy ( IProcessWithDifferentiator<TResult, TItem, TDiff> px ) { _proxyTo = px; }
    private IProcessWithDifferentiator<TResult, TItem, TDiff> _proxyTo;
    TResult IProcess<TResult, TItem>.Process ( TItem item ) { return _proxyTo.Process ( item ); }
}

public interface IRoot<TR1, TR2, TR3, TItem1, TItem2, TItem3> :
    IProcess<TR1, TItem1>,
    IProcessWithDifferentiator<TR2, TItem2, Second>,
    IProcessWithDifferentiator<TR3, TItem3, Third>
{
}

class Program
{
    static void Main ( string [] args )
    {
        Processor p = new Processor ();
        // Direct conversion of first one, of course
        IProcess<float, float> a1 = p;
        System.Console.WriteLine ( "a1 .Process(3.3)   =    " + a1.Process ( (float) 3.3 ) );

        // Conversion of differentiated class
        IProcessWithDifferentiator<int, int, Second> a2 = ((IProcessWithDifferentiator<int, int, Second>) p);
        System.Console.WriteLine ( "a2d.Process(4)     =    " + a2.Process ( 4 ) );
        IProcessWithDifferentiator<double, double, Third> a3 = (IProcessWithDifferentiator<double, double, Third>) p;
        System.Console.WriteLine ( "a3d.Process(5.5)   =    " + a3.Process ( 5.5 ) );

        // Conversions to undifferentiated class using ugly proxies
        IProcess<int, int> a2u = ((IProcessWithDifferentiator<int, int, Second>) p).ConvertToBase ();
        System.Console.WriteLine ( "a2u.Process(4)     =    " + a2u.Process ( 4 ) );
        IProcess<double, double> a3u = ((IProcessWithDifferentiator<double, double, Third>) p).ConvertToBase ();
        System.Console.WriteLine ( "a3u.Process(5.5)   =    " + a3u.Process ( 5.5 ) );

        TestProcessor q = new TestProcessor ();

        IProcess<int, int> b1 = q;
        // Direct conversion of first one, of course
        System.Console.WriteLine ( "b1 .Process(3)     =    " + b1.Process ( 3 ) );

        // Conversion of differentiated class
        IProcessWithDifferentiator<int, int, Second> b2d = (IProcessWithDifferentiator<int, int, Second>) q;
        System.Console.WriteLine ( "b2d.Process(4)     =    " + b2d.Process ( 4 ) );
        IProcessWithDifferentiator<int, int, Third> b3d = (IProcessWithDifferentiator<int, int, Third>) q;
        System.Console.WriteLine ( "b3d.Process(5)     =    " + b3d.Process ( 5 ) );

        // Conversions to undifferentiated class using ugly proxies
        IProcess<int, int> b2u = ((IProcessWithDifferentiator<int, int, Second>) q).ConvertToBase ();
        System.Console.WriteLine ( "b2u.Process(4)     =    " + b2u.Process ( 4 ) );
        IProcess<int, int> b3u = ((IProcessWithDifferentiator<int, int, Third>) q).ConvertToBase ();
        System.Console.WriteLine ( "b3u.Process(5)     =    " + b3u.Process ( 5 ) );

        System.Console.ReadLine ();
    }
}

输出如下:

  ...float Process...
a1 .Process(3.3)   =    -52.45
  ...int Process...
a2d.Process(4)     =    5
  ...double Process...
a3d.Process(5.5)   =    16.248
  ...int Process...
a2u.Process(4)     =    5
  ...double Process...
a3u.Process(5.5)   =    16.248
  ...int Process1...
b1 .Process(3)     =    -8
  ...int Process2...
b2d.Process(4)     =    16
  ...int Process3...
b3d.Process(5)     =    100307
  ...int Process2...
b2u.Process(4)     =    16
  ...int Process3...
b3u.Process(5)     =    100307

问题恰恰是错误消息说的是:

'IRoot<TM,TPM,TPK>' cannot implement both 'IBase<TM,TPK>' and
'IBase<TPM,TPK>' because they may unify for some type parameter substitutions

例如,您可以执行以下操作:

public class Test : IRoot<Int32, Int32, Int32>

在这种情况下,它将有两个到IBase<Int32, Int32>继承链IBase<Int32, Int32>这是不允许的。

与往常一样,请尽量提供您所面临的问题以及该问题的代码。

据我了解,您想定义一个像这样的接口:

public interface IRoot<TM, TPM, TPK>
  where TM : MType
  where TPM : PMType
  where TPK : new()
{
  TM Get(TPK key);
  TPM Get(TPK key);
}

这是不可能的,因为您不能使用相同的名称和相同的参数来定义两个方法。

error CS0111: Type 'IRoot<TM,TPM,TPK>' already defines a member called 'Get' with the same parameter types

尝试直接定义您的接口(不继承)并更改方法名称。 例如:

public interface IRoot<TM, TPM, TPK>
  where TM : MType
  where TPM : PMType
  where TPK : new()
{
  TM GetTM(TPK key);
  TPM GetTPM(TPK key);
}

很抱歉看到您对此有很多反对意见,我也面临着同样的问题。

令人遗憾的是,似乎不可能-这个MSDN页面列出了唯一可能的通用类型约束,没有人可以表达约束“ TU可以是任何类型,但必须具有不同的继承层次结构” http://msdn.microsoft .com / zh-CN / library / d5x73970(v = vs.80).aspx

我们确实需要某种形式的where T !: Uwhere T, U disjoint语法; 但是就目前情况而言,无法向编译器指定TItem1TItem2实例永远不能相互替代。

您可能会使用这种实现。 您将松散一些通用参数:

public interface IBase<TM, TPkey> 
    where TM : bType
    where TPkey : new ()        
{
    TM Get(TPkey key);
}

public interface IABase<TPK> : IBase<ConcreteTmA, TPK> {}
public interface IBBase<TPK> : IBase<ConcreteTmB, TPK> {}

public class Root <TPK> :
    IABase<TPK>,
    IBBase<TPK> 
    where TM : MType 
    where TPM : PMType 
    where TPK : new()
{
    ConcreteTmA IABase.Get(TPK key)
    {
    }

    ConcreteTmB IBBase.Get(TPK key)
    {
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM