是否有更好的替代方法来定义静态接口方法/属性?

时间:2016-02-23 16:31:41

标签: c#

对我来说,为什么C#不支持静态方法&接口中的静态属性。在对该问题的其他SO问题的简要调查中,我遇到了各种各样的答案,其中显然是对C#和/或CLR设计的疏忽,修复它会破坏现有的代码"一直到"接口都是为了与对象进行交互,如果你发现自己想要使用其他接口,你显然缺少灰质,应该回到扫地......#34;。 This question展示了所有这些答案。

我需要一个解析器系列,每个解析器都有一个方法,用于确定传递给它的程序集文件内容是否与其平台类型匹配。这些是无国籍实体;没有理由拥有"对象"这些解析器除了C#接口需要类实例之外。如果我撕掉所有" static"下面的关键字,此代码编译没有错误。

  public interface IParser
  {
     static string platformName { get; }
     static bool isThisPlatform(string asmFileContents);
     static bool parseAsm(string asmFileContents);
  }

  class PIC32MX_GCC_Parser : IParser
  {
     public static string platformName { get { return "PIC32MX_GCC"; } }
     public static bool isThisPlatform(string asmFileContents)
     {
        return false; // stub
     }
     public static bool parseAsm(string asmFileContents)
     {
        return false; // stub
     }
  }

  class M16C_IAR_Parser : IParser
  {
     public static string platformName { get { return "M16C_IAR"; } }
     public static bool isThisPlatform(string asmFileContents)
     {
        return false; // stub
     }
     public static bool parseAsm(string asmFileContents)
     {
        return false; // stub
     }
  }

  IParser[] parsers =
  {
     new PIC32MX_GCC_Parser(),
     new M16C_IAR_Parser()
  };

  public IParser findTheRightParser(string asmFileContents)
  {
     foreach(IParser parser in parsers)
     {
        if (parser.isThisPlatform(asmFileContents))
        {
           Console.WriteLine("Using parser: ", parser.platformName);
           return parser;
        }
     }
     return null;
  }

我想问为什么C#不会让我这样做,但我知道答案只是"因为它没有。"我知道"解决方法"是将它们实现为实例方法,如果需要,可以调用静态方法(在这种情况下实际上并不需要)。

由于有许多人(许多具有高SO代表)认为在接口中放置静态方法没有逻辑意义,如果你想这样做,你的设计有问题,或者你的头(或两者),我希望其中一些人能帮助我给我一个很好的,简单的替代我的代码,上面的代码使用静态方法,而不是简单的"解决"实例方法包装静态方法的问题。

2 个答案:

答案 0 :(得分:1)

需要对象,因为您看起来正在寻找的是dynamic dispatch - 您希望能够在接口(IParser.Parse)上调用方法,但是要实现方法由接口的具体实现定义。这是经典的OOP,C#(以及Java)仅通过实例方法支持它。单身人士无需每次通话分配,因此这是一种很好的方法。或者你使用静态类和静态方法 - 但是你只能使用静态调度,因为调用者必须知道要调用哪个实现。

简而言之,它不是C#限制。它是大多数(如果不是全部)面向对象编程语言的限制。

C#文献中有许多单例实现的例子(例如:http://www.dotnetperls.com/singleton)。

要想出其他选择,需要更改选择解析器的方式。例如,如果您想通过枚举选择它:

enum ParserType {
    PIC32MX_GCC,
    M16C_IAR,
    Other_Parser,
}

然后这样的事情会起作用:

public static bool parseAsm(ParserType type, string asmFileContents) {
    switch type {
        case PIC32MX_GCC:
            return PIC32MX_GCC_Parser.ParseAsm(asmFileContents);
        case M16C_IAR:
            return M16C_IAR_Parser.ParseAsm(asmFileContents);
        default:
            throw new NotImplementedException("I dont know this parser type");
    }
}

你也可以通过反思来做你已经尝试做的事情(但表现非常糟糕):

Type[] parsers =
  {
     typeof(PIC32MX_GCC_Parser),
     typeof(M16C_IAR_Parser)
  };

  public Type findTheRightParser(string asmFileContents)
  {
     foreach(Type parser in parsers)
     {
        // You probably want to cache this
        var mi = parser.GetMethod("isThisPlatform", BindingFlags.Static);
        if ((Boolean)mi.Invoke(null, new object[] {asmFileContents}))
        {
           Console.WriteLine("Using parser: ", parser.platformName);
           return parser;
        }
     }
     return null;
  }

答案 1 :(得分:0)

您不能拥有静态接口,但如果切换到重定向到静态字段的单例,则可以获得所需的行为。因为您使用单例并且单例不保存数据,所以它具有非常低的内存开销,每种类型只有几个字节。

public interface IParser
{
    string platformName { get; }
    bool isThisPlatform(string asmFileContents);
    bool parseAsm(string asmFileContents);
}

class PIC32MX_GCC_Parser : IParser
{
    private PIC32MX_GCC_Parser()
    {
    }

    public static string platformName { get { return "PIC32MX_GCC"; } }


    public static bool isThisPlatform(string asmFileContents)
    {
        return false; // stub
    }

    public static bool parseAsm(string asmFileContents)
    {
        return false; // stub
    }

    private static readonly PIC32MX_GCC_Parser _instance = new PIC32MX_GCC_Parser();

    public static IParser Instance
    {
        get { return _instance; }
    }

    string IParser.platformName { get { return platformName; } }

    bool IParser.isThisPlatform(string asmFileContents)
    {
        return isThisPlatform(asmFileContents);
    }

    bool IParser.parseAsm(string asmFileContents)
    {
        return parseAsm(asmFileContents);
    }
}

class M16C_IAR_Parser : IParser
{
   //..snip
}

Parser[] parsers =
{
 PIC32MX_GCC_Parser.Instance,
 M16C_IAR_Parser.Instance
};

public IParser findTheRightParser(string asmFileContents)
{
    foreach (IParser parser in parsers)
    {
        if (parser.isThisPlatform(asmFileContents))
        {
            Console.WriteLine("Using parser: ", parser.platformName);
            return parser;
        }
    }
    return null;
}

但是,如果我在这里,我会删除静态方法并将所有数据放在单例内。