对我来说,为什么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代表)认为在接口中放置静态方法没有逻辑意义,如果你想这样做,你的设计有问题,或者你的头(或两者),我希望其中一些人能帮助我给我一个很好的,简单的替代我的代码,上面的代码使用静态方法,而不是简单的"解决"实例方法包装静态方法的问题。
答案 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;
}
但是,如果我在这里,我会删除静态方法并将所有数据放在单例内。