【问题标题】:Is it possible to create an interface this general?是否可以创建一个通用的接口?
【发布时间】:2016-06-01 22:42:31
【问题描述】:

我要创建很多类,比如

public static class M2SA
{
    // Median of 2 sorted arrays

    public static int Method ( int[] A, int[] B )
    {
        int m = A.Length, n = B.Length;
        if((m | n) == 0) 
            throw new ArgumentException("A and B cannot both be empty");
        int i = 0, j = 0, k = (m + n)/2; 
        while((i + j) < k)
        {
            if(i == m) ++j;
            else if(j == n || A[i] <= B[j]) ++i;
            else ++j;
        }
        if(i == m) return B[j];
        else if(j == n) return A[i];
        else return Math.Min(A[i],B[j]);
    }

    public static int Alternative ( int[] A, int[] B )
    {
        if ((A.Length | B.Length) == 0)
            throw new ArgumentException("A and B cannot both be empty");
        int[] mergedAndSorted = A.Concat(B).OrderBy(x => x).ToArray();
        return mergedAndSorted[mergedAndSorted.Length / 2];
    }

    public static bool Test ()
    {
        return false;//Placeholder - haven't implemented yet
    }
}

因为他们都会实施

  • 一个名为Methodpublic static 方法
  • 一个名为Alternativepublic static 方法与Method 具有相同的签名
  • 一种方法public static bool Test,用于测试MethodAlternative 是否为给定的一组生成的输入产生等效的输出。

这些类可能有其他方法作为助手。

有没有一种方法可以创建一个足够通用的接口,它需要上述内容,但除此之外一无所知?还是要求其方法具有某些签名?

例如,我可能有另一个类,如

public static class UnstablePartition
{

    public static void intswap(ref int a, ref int b)
    {
        // I'm amazed that there isn't already a method for this in the .NET library (???)
        int temp = a;
        a = b;
        b = temp;
    }

    public delegate bool UnaryPredicate (int i);

    public static void Method ( int[] arr, UnaryPredicate pred )
    {
        for(int i = 0, j = arr.Length; i < j; )
        {
            if (!pred(arr[i])) ++i;
            else if (pred(arr[j])) --j;
            else intswap(ref arr[i],ref arr[j]);
        }
    }

    public static void Alternative(int[] arr, UnaryPredicate pred)
    {
        int[] partioned = new int[arr.Length];
        for (int ai = 0, pi = 0, pj = partioned.Length; ai < arr.Length; ++ai)
        {
            if (pred(arr[ai])) partioned[pj--] = arr[ai];
            else partioned[pi++] = arr[ai];
        }
        Array.Copy(partioned, arr, partioned.Length);
    }


    public static bool Test()
    {
        return false;//Placeholder - haven't implemented yet
    }

}

所以我想要一个类似的界面(我知道下面是完全无效...)

public static interface InterviewQuestion
{
    public static Method;
    public static Alternative;
    public static bool Test();
}

然后我会像这样实现它

public static class M2SA : InterviewQuestion

【问题讨论】:

  • 是否可以使用静态成员创建静态接口?...不。
  • 接口不能是static 也不能是它的成员
  • “静态界面”的意义何在?没有静态继承——如果你调用一个静态方法,你就是在指定你的意思是哪个类。解决这个问题的方法是让你的类是非静态的。
  • 即使可以在接口中定义静态方法......如果它们有不同的签名又有什么意义呢?编译器如何知道这些静态方法需要哪些参数?

标签: c# .net oop inheritance


【解决方案1】:

Interfaces (C# Programming Guide) 可以包含方法、属性、事件、索引器或这四种成员类型的任意组合...接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型。接口成员是自动公开的,它们不能包含任何访问修饰符。 成员也不能是静态的。

这意味着你的界面看起来像

public interface InterviewQuestion
{
    int Method(int[] a, int[] b);
    int Alternative(int[] a, int[] b);
    bool Test();
}

你的课程看起来像

public class M2SA : InterviewQuestion
{
    public int Alternative(int[] a, int[] b)
    {
        // implementation
    }

    public int Method(int[] a, int[] b)
    {
        // implementation
    }

    public bool Test()
    {
        // implementation
    }
}

public class UnstablePartition : InterviewQuestion
{
    public int Alternative(int[] a, int[] b)
    {
        // implementation
    }

    public int Method(int[] a, int[] b)
    {
        // implementation
    }

    public bool Test()
    {
        // implementation
    }
}

或者您可以使用abstract class。然后你的实现看起来像

public abstract class InterviewQuestion
{
    public abstract int Method(int[] a, int[] b);
    public abstract int Alternative(int[] a, int[] b);
    public abstract bool Test();
}

public class M2SA : InterviewQuestion
{
    public override int Alternative(int[] a, int[] b)
    {
        // implementation
    }

    public override int Method(int[] a, int[] b)
    {
        // implementation
    }

    public override bool Test()
    {
        // implementation
    }
}

public class UnstablePartition : InterviewQuestion
{
    public override int Alternative(int[] a, int[] b)
    {
        // implementation
    }

    public override int Method(int[] a, int[] b)
    {
        // implementation
    }

    public override bool Test()
    {
        // implementation
    }
}

【讨论】:

  • 我同意了。接口不能是静态的。所以你只需要去掉static 关键字。这可能会让您感到困惑,因为您可能会认为“no state 为什么我需要传递this 指针?”但实际上是有状态的,这个状态是指向类方法的指针。
【解决方案2】:

这样的事情呢? :

public interface InterviewQuestion<T, TResult>
{
    TResult Method (Func<T, TResult> func);
    TResult Alternative (Func<T, TResult> func);
    bool Test ( );
}

public class M2SA : InterviewQuestion<Tuple<int[], int[]>, int>
{
    private static Lazy<M2SA> lazy = new Lazy<M2SA>(() => new M2SA(), true);

    public static M2SA Instance => lazy.Value;

    public int Alternative (Func<Tuple<int[], int[]>, int> func)
    {
        throw new NotImplementedException();
    }

    public int Method (Func<Tuple<int[], int[]>, int> func)
    {
        throw new NotImplementedException();
    }

    public bool Test ( )
    {
        throw new NotImplementedException();
    }
}

您仍然使用常规接口并使用Singleton 模式来模仿静态类

【讨论】:

    【解决方案3】:

    其他答案评论了您正在尝试制作静态界面这一事实。

    我认为这里更深层次的问题是您试图创建一个方法签名不一致的接口。

    有没有一种方法可以创建一个足够通用的接口,它需要上述内容,但除此之外一无所知?还是要求它的方法有特定的签名?

    您基本上要求创建一个带有未知方法参数的部分接口。接口必须具有明确定义的签名。

    你可以做的是将参数分离到不同的接口或类,例如

    public interface IInterviewQuestion
    {
        int Method(IQuestionInput qParams);
        int Alternative(IQuestionInput qParams);
        bool Test();
    }
    

    即便如此,方法的返回类型也必须是constant不变的。

    当然,IQuestionInput 可能包含任何内容,这将有多大用处取决于您需要如何使用这些问题。

    【讨论】:

    • 通用接口将允许方法的返回类型不再是不变量(“常量”与“变量”相反,这两个概念都指的是值,而不是类型 - - 你想要的“常量”实际上是“不变的”)。
    • @pid 我认为泛型在这里没有多大价值,因为你最终不能拥有一组混合的T 来操作,我认为这是目标。重新“恒定”,已修复,谢谢。
    【解决方案4】:

    您可以使用Monostate 模式来解决这个问题。引用网站:

    单态是“概念上的单例”——一个单态的所有数据成员 单态是静态的,所以单态的所有实例都使用相同的 (静态)数据。使用单态的应用程序可以创建任意数量的 他们想要的实例,因为每个实例都使用相同的数据。什么 我发现单态类的好处是它们避免了所有 必须访问类的特定实例的复杂性。 任何实例都与另一个实例一样好。我发现单态确实添加 对于那些沉浸在 GOF Singletons 中的人来说有些困惑,这可能是 一件坏事。

    基本上,您无需使用静态类,而是将它们设为常规类。但是,在内部,它们的行为就像它们是静态的一样。成员变量是静态的,因此它们可以在类的实例之间共享。

    这种方法允许您针对类实现接口。这也意味着您可以根据需要通过那里的接口依赖注入类。此外,如果您决定想要/需要特定于实例的数据,那么它更容易实现。

    注意:在您的情况下,没有状态,因此您将实现该模式以允许您针对具体类型实现接口或抽象类。

    【讨论】:

    • 这是否与问题直接相关? OP 的类是无状态的——实际上看起来它们不需要 是静态类。
    • @TimBarrass - 他们是无国籍的并不重要。它们实际上是单例,他正在寻求针对它们实现接口。 Monostate 模式允许这样做,只是在他的情况下没有状态!
    • 根据你的描述,没有任何状态的单态只是一个类——我错过了什么吗?
    • @TimBarrass - 不同之处在于它不是静态的。目前没有状态,我猜这就是他将它们设为静态的原因。但是,他遇到了语言障碍,即他无法在它们上实现接口。这种方法解决了这个问题,即使实例没有状态,所以在概念上是静态的。如果他确实需要添加状态,他也会被覆盖。
    • 如果它们是静态的,因为它们没有状态,那么可以合理地假设拥有状态不是必需的。使用单态(虽然很有趣,但我之前没有将其视为命名模式)则大体上是无关紧要的,因为有用的只是将它们转换为普通类。
    【解决方案5】:

    你不能有静态接口。为了利用接口,您必须使其成为常规成员方法。

    你可以有这个界面:

    public interface InterviewQuestion<T1, T2>
    {
        public Method<T1 arg1, T2 arg2>();
        public Alternative<T1 arg1, T2 arg2>();
        public bool Test();
    }
    

    然后你实现它:

    public class M2SA : InterviewQuestion<int[], int[]>
    {
      //...
    }
    

    以及对它的静态访问(或者通过 T1 访问它甚至更动态,例如,存储库,无论如何,这是最简单的静态方式):

    public static class InterviewQuestions
    {
      private static M2SA m2sa = new M2SA();
      public static M2SA M2SA => m2sa;
    
      // ...
    }
    

    访问:

    InterviewQuestions.M2SA.Method(blah, blah);
    

    在您开始编写未静态绑定到其中一种实现的代码之前,这并没有太大的价值。您可以通过 T1 或 T2 或两者或其他搜索条件找到实现。您可以创建一个没有泛型参数的接口,并为方法提供对象参数,这允许在不知道类型的情况下调用它。等等。

    【讨论】:

      猜你喜欢
      • 2019-03-19
      • 2020-08-23
      • 2021-07-20
      • 1970-01-01
      • 1970-01-01
      • 2011-09-16
      • 2020-08-26
      • 1970-01-01
      • 2011-02-22
      相关资源
      最近更新 更多