我很困惑为什么new
运算符没有像我预期的那样工作。
注意:以下所有类都在同一名称空间和同一文件中定义。
此类允许您使用一些提供的文本为写入控制台的任何内容添加前缀。
public class ConsoleWriter
{
private string prefix;
public ConsoleWriter(string prefix)
{
this.prefix = prefix;
}
public void Write(string text)
{
Console.WriteLine(String.Concat(prefix,text));
}
}
这是一个基类:
public class BaseClass
{
protected static ConsoleWriter consoleWriter = new ConsoleWriter("");
public static void Write(string text)
{
consoleWriter.Write(text);
}
}
这是一个实现的类:
public class NewClass : BaseClass
{
protected new static ConsoleWriter consoleWriter = new ConsoleWriter("> ");
}
现在这是执行此操作的代码:
class Program
{
static void Main(string[] args)
{
BaseClass.Write("Hello World!");
NewClass.Write("Hello World!");
Console.Read();
}
}
所以我希望输出为
Hello World!
> Hello World!
但输出是
Hello World!
Hello World!
我不明白为什么会这样。以下是我的思考过程:
BaseClass.Write()
方法BaseClass.consoleWriter
成员。BaseClass.consoleWriter
变量然后
NewClass.Write()
NewClass.consoleWriter
对象。 BaseClass
,但该方法是通过NewClass
变量NewClass.consoleWriter
)执行该方法
醇>
我认为这是继承结构的工作方式吗?
请有人帮我理解为什么这不起作用?
-
更新:
此方案可以如下工作(我是如何实现的)
public class LogBase
{
protected static TraceSource logger = new TraceSource("");
public static void Error (string text) { logger.WriteError(text); }
public static void Info (string text) { logger.WriteInformation(text); }
public static void Warning (string text) { logger.WriteWarning(text); }
public static void Verbose (string text) { logger.WriteVerbose(text); }
}
// DataAccess logging
public class DALog : LogBase
{
protected new static TraceSource logger = new TraceSource("DataAccess");
}
// BusinessObjects logging
public class BOLog : LogBase
{
protected new static TraceSource logger = new TraceSource("Objects");
}
// BusinessLogic logging
public class BLLog : LogBase
{
protected new static TraceSource logger = new TraceSource("Logic");
}
// WebUI logging
public class WebUILog : LogBase
{
protected new static TraceSource logger = new TraceSource("WebUI");
}
原因是我不必为每个类复制代码。
-
更新(选择解决方案后):
因此,为了解决这个问题,我没有使用基类,而是定义了一个功能。然后创建了新类,为每个层保存了Singleton实例:
public sealed class LogBase
{
private TraceSource logger = null;
public static LogBase GetLogger(string loggerName)
{
return new LogBase(loggerName);
}
private LogBase(string loggerName) { logger = new TraceSource(loggerName); }
public void Error (string text) { logger.WriteError(text); }
public void Info (string text) { logger.WriteInformation(text); }
public void Warning (string text) { logger.WriteWarning(text); }
public void Verbose (string text) { logger.WriteVerbose(text); }
}
// DataAccess logging - no base class
public class DALog
{
private static LogBase logger;
public static LogBase Instance
{
get
{
if (logger==null) { logger = new TraceSource("DataAccess"); }
return logger;
}
}
}
...
答案 0 :(得分:9)
new
运算符在多态性意义上实际上没有覆盖。它只是添加了另一种“发生”的方法,它具有相同的签名,但却被视为一种单独的方法。只有在子类上显式执行该方法时,才会使用“新”实现。
在您的情况下,您仅在基类上实现了Write
。在那里,你有一行调用consoleWriter
。 该行指的是基类 ,因此使用原始实现。它甚至不知道子类中的其他实现。
检查您的代码并按原样考虑:
public class BaseClass
{
protected static ConsoleWriter consoleWriter = new ConsoleWriter("");
public static void Write(string text)
{
consoleWriter.Write(text);
}
}
public class NewClass : BaseClass
{
protected static ConsoleWriter anotherConsoleWriter = new ConsoleWriter(">");
}
你的BaseClass.Write不会考虑调用anotherConsoleWriter而不是consoleWriter。
如果您希望自己的示例有效,则需要为Write
添加新实现:
public class NewClass : BaseClass
{
protected new static ConsoleWriter consoleWriter = new ConsoleWriter(">");
public static new void Write(string text)
{
consoleWriter.Write(text);
}
}
...或者,您最初可能想要的,而是使用override
而不是new
来介绍真正的覆盖多态性。但是,您的基类需要通过将consoleWriter声明为virtual
来支持它。此外(正如您在评论中提到的),只有在您不将这些方法设为静态时,此方法才有效。
如果您仍想要对记录器进行静态访问,或者查看已经为您解决了所有这些问题的Singleton pattern,则可以应用log4net。
答案 1 :(得分:3)
你遗漏了几个关键点。静态使它成为一个班级领域。受保护意味着它可以从派生类中获得。新意味着您隐藏了基本成员。
你需要这些类是静态的吗?如果不是,您可以将Write方法设为虚拟并在派生类中覆盖它; base.Write(“>”+ text);
答案 2 :(得分:3)
原始问题已被其他人回答:OP期望的行为是覆盖方法的结果,而不是使用new
得到的结果。
在OP的回答中,他担心你不能覆盖静态方法。这是真的,但这里有一个来自msdn的博客,它既解释了原因,又讨论了处理它的方法: http://blogs.msdn.com/b/kirillosenkov/archive/2008/02/06/how-to-override-static-methods.aspx
答案 3 :(得分:1)
你知道继承和覆盖适用于(虚拟)实例方法,而不是静态方法,对吗?
您的覆盖为protected
,因此在NewClass
及其后代之外无法显示。因此,行为是按规格。 new
仅允许您创建一个新功能,该功能可在其上下文中使用相同的标识符引用:您的NewClass.Write
方法实际上与您的BaseClass.Write
无关。