C# 如何根据程序显示消息';自然

C# 如何根据程序显示消息';自然,c#,C#,对不起,我的文字太长了 我有一个C#类库,它从各种系统检索信息,调用外部函数,验证这些信息,并生成文件验证结果。此库可以通过以下方式调用:1)DOS控制台程序、2)Windows窗体或3)Windows服务程序 用户要求我修改库,使其能够以详细的方式运行,即显示特定步骤的日期和时间,简要说明特定步骤或方法正在执行的操作,等等。他们还要求我引入异常处理并显示错误消息 如果在控制台模式下执行,则应在控制台上显示消息;如果从Windows窗体执行,则应将消息发送到消息框或文本框;如果从Windows服

对不起,我的文字太长了

我有一个C#类库,它从各种系统检索信息,调用外部函数,验证这些信息,并生成文件验证结果。此库可以通过以下方式调用:1)DOS控制台程序、2)Windows窗体或3)Windows服务程序

用户要求我修改库,使其能够以详细的方式运行,即显示特定步骤的日期和时间,简要说明特定步骤或方法正在执行的操作,等等。他们还要求我引入异常处理并显示错误消息

如果在控制台模式下执行,则应在控制台上显示消息;如果从Windows窗体执行,则应将消息发送到消息框或文本框;如果从Windows服务运行,则应将消息发送到日志文件

我有两个问题:

1) 我应该如何修改C#类以避免不断求值: 如果程序处于控制台模式writeline…。。 否则,如果程序处于windows窗体模式messagebox或textbox.text… 否则,如果从windows服务程序writelogfile调用程序

2) 如果上述评估不可避免,我如何知道控制台windows窗体windows服务程序是否正在调用C#类库

谢谢


可能的解决办法:


我读了一些关于微软企业图书馆和。。。这对我的适度要求来说太多了,所以我选择了里德的务实解决方案

我分享我解决用户需求的方法,这是应用到实际情况之前的初步模型,因此,在接受Reed解决方案之前,欢迎您提出改进和学习的意见

1) 我创建了一个小库来定义所有可能的输出,在本例中,我只定义了控制台和WPF表单的输出:

名称空间二类 { 公共接口 { 无效显示(字符串消息,对象文本框); 无效通知(字符串消息); }

}

2) 然后我定义了一个使用上述库的控制台程序:

class Program
{
    static void Main(string[] args)
    {
        IVerbose verboseType = (IVerbose)Activator.CreateInstance(typeof(diClass.ConsoleOutput));
        Output o = new Output();
        o.verboseType = verboseType;
        object textBox1 = null;
        o.show(string.Format("{0}: Reading Accountig data", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")), textBox1);
        o.notify(string.Format("{0}: Application error", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")));
    }
}
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        IVerbose verboseType = (IVerbose)Activator.CreateInstance(typeof(diClass.WpfOutput));
        Output o = new Output();
        o.verboseType = verboseType;
        o.show(string.Format("{0}: Reading Accountig data", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")), textBox1);
        o.notify(string.Format("{0}: Application error", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")));
    }
}
3) 最后,我定义了一个WPF程序,它也使用上述库:

class Program
{
    static void Main(string[] args)
    {
        IVerbose verboseType = (IVerbose)Activator.CreateInstance(typeof(diClass.ConsoleOutput));
        Output o = new Output();
        o.verboseType = verboseType;
        object textBox1 = null;
        o.show(string.Format("{0}: Reading Accountig data", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")), textBox1);
        o.notify(string.Format("{0}: Application error", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")));
    }
}
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        IVerbose verboseType = (IVerbose)Activator.CreateInstance(typeof(diClass.WpfOutput));
        Output o = new Output();
        o.verboseType = verboseType;
        o.show(string.Format("{0}: Reading Accountig data", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")), textBox1);
        o.notify(string.Format("{0}: Application error", DateTime.Now.ToString("dd/MM/yy hh:mm:ss")));
    }
}
在程序2)和3)中,最后两行代码相等,没有ifs,这就是我想要的答案


关于。

与其尝试处理所有这些情况,不如考虑添加写入详细日志的日志记录(例如,或任何其他日志记录工具),这将帮助您满足所有要求,即时间戳、方法执行信息、异常、错误

有一个事件,在异常情况下显示消息/警报

public event Action<string> Message;
公共事件行动信息;

允许任何想要处理该消息的UI,只需添加自己的委托。

对于这种情况,我的首选是创建一组接口,并针对这些接口工作。然后,您可以使用依赖项注入来注入接口的具体版本,这取决于您是在控制台、gui中运行,还是作为服务运行。类似(这是一个非常简单的版本):

然后,让我们看一下控制台应用程序版本。您只需为控制台应用程序提供正确的
IAlgorithmFactory

class ConsoleAlgorithm : IAlgorithm
{
    string name;
    public ConsoleAlgorithm(string algorithmName)
    { 
        this.name = algorithmName;
    }
    public void UpdateProgress(double percent)
    {
        if(percent == 0)
            Console.WriteLine();
        else if (percent == 1.0)
            Console.WriteLine("100%        ");
        else
            Console.Write("\r{0}%", percent * 100);
    }
    public void Complete(bool success)
    {
        if (success)
            Console.WriteLine("{0} completed successfully.", this.name);
        else
            Console.WriteLine("{0} failed.");
    }
    public void Error(string error)
    {
        Console.WriteLine("{0} received error: {1}", this.name, error);
    }
}

public class ConsoleAlgorithmFactory: IAlgorithmFactory
{
    public IAlgorithm StartAlgorithm(string name)
    {
        return new ConsoleAlgorithm(name);
    }
}
当您的程序作为控制台运行时,您会为它提供一个
ConsoleAlgorithmFactory
,它只会将其用作
IAlgorithmFactory
。你可以调用它上面的方法来报告进度,而你的主程序并不关心它是如何运行的——它只是根据需要进行报告


另一方面,当您作为GUI运行时,您会制作类似于
WindowsFormsAlgorithmFactory的东西,并将其传入,现在报告将通过表单完成。。。程序中没有任何更改。

这可能不太适合GUI环境,但非常适合console+服务。这比使用事件有什么好处?在您的模型中,如果有人不想听某些动作,您将使用退化方法。您可以为每个方法创建一个接口,但这似乎已经内置到事件中。您可以以非常丰富的方式传递更多信息,比使用事件更简单。当然,在这种情况下(我发布的内容),事件也会起作用。事件的另一个“问题”是事件是基于订阅者的——因此“表单”需要了解、理解并访问程序内部,至少是事件的部分。这可能很简单,但也可能(在某些情况下)很困难,需要对api进行重大更改。这是基于推送的——程序中的“逻辑”只是说“我想这样做”,由演示决定是否处理它。这实际上取决于您是否希望外部世界需要了解您的算法(在这种情况下,观察者模式是有意义的),或者您希望您的逻辑工作,并且能够创建“报告”或“gui”类,而不知道使用的是什么具体版本,这就是我所做的(抽象工厂模式)。在这种情况下,您可以使用任何一种方法—这取决于您传递的信息量、您希望如何构造API以及您希望在何处引入抽象级别。您能解释一下您所说的可以传递更多信息的意思吗?我相信事件在这种情况下会更好地工作,因为您有许多订户和一个服务。从维护的角度来看,如果您使用的是接口,那么添加另一个方法将需要更改每个UI或创建另一个接口来处理它。对于事件,只需添加另一个事件,并允许需要它的UI向其添加委托。也许我看不出添加公开事件比拥有一个接受接口并将其传递下去的构造函数更困难,我可以看到服务如何通过强制UI t命令UI