0

所以我有许多不同的潜在对象可以输出数据(字符串)。我想要做的是运行一个通用的 Output.WriteLine 函数,其潜在参数定义了您希望将其输出到的位置。我有什么代码 -

//Defined in static class Const
public enum Out : int { Debug = 0x01, Main = 0x02, Code = 0x04 };

static class Output
{
    private static List<object> RetrieveOutputMechanisms(Const.Out output)
    {
        List<object> result = new List<object>();

    #if DEBUG
        if (bitmask(output, Const.Out.Debug))
            result.Add(1);//Console); //I want to add Console here, but its static
    #endif
        if (bitmask(output, Const.Out.Main))
            if (Program.mainForm != null)
                result.Add(Program.mainForm.Box);

        if (bitmask(output, Const.Out.Code))
            if (Program.code!= null)
                result.Add(Program.code.Box);

        return result;
    }

    public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
    {
        Console.WriteLine(
        List<object> writers = RetrieveOutputMechanisms(output);
        foreach (object writer in writers)
            writer.WriteLine(str, color);
    }
}

重点在于,输出目的地并不总是存在,因为它们在调用这些调用时可能存在也可能不存在的表单上。所以想法是确定您要打印到哪些,确定它是否存在,将其添加到要打印到的事物列表中,然后循环并打印到所有这些,如果它们实现了“WriteLine”方法.

我遇到的两个问题是

  1. 该控制台是一个静态类,不能正确(据我所知)添加到对象列表中。
  2. 我不知道如何断言列表中的对象定义了 WriteLine,并将它们转换为适用于多个基本类型的东西。假设我可以让控制台在这个方案中正常工作,这将是一个明显的问题,它的基本类型与实际的盒子不同,而且,如果我有一些不是盒子的东西,那么做起来会很可爱就像是

    foreach(作家中的对象作家).WriteLine(str,color)

这样我就不必单独投射它们了。

我不简单地从 RetrieveOutputMechanisms 函数中写入 WriteLine 的更大原因是,我希望它不仅仅涵盖 WriteLine,这意味着我需要将位掩码代码复制到每个函数。

编辑:我意识到将公共属性添加到 Program 是一个坏主意,如果你知道我可以如何避免它(必要性来自需要能够从任何地方访问任何来来去去的 WriteLine 表单对象),通过一切手段请详细说明。

4

3 回答 3

1

一种方法是使用Action(委托)并将它们存储在您的List. 这适用于Console任何其他类,因为您可以轻松编写 lambda(或 2.0 委托)将输出变量映射到被调用方法中的正确参数。将不需要铸造。它可以像这样工作:

(这假设您使用的是 C# 3.5 或更高版本,但您可以在 2.0 和使用委托的任何内容中执行所有这些操作)

static class Output
{
    private static List<Action<string, Color>> RetrieveOutputMechanisms(Const.Out output)
    {
        List<Action<string, Color>> result = new List<string, Color>();

    #if DEBUG
        if (bitmask(output, Const.Out.Debug))
            result.Add((s, c) => Console.WriteLine(s, c)); //I want to add Console here, but its static
    #endif
        if (bitmask(output, Const.Out.Main))
            if (Program.mainForm != null)
                result.Add((s, c) => Program.mainForm.Box.WriteLine(s, c));

        if (bitmask(output, Const.Out.Code))
            if (Program.code!= null)
                result.Add((s, c) => Program.code.Box.WriteLine(s, c));

        return result;
    }

    public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
    {
        var writers = RetrieveOutputMechanisms(output);
        foreach (var writer in writers)
            writer(str, color);
    }
}

(编辑添加)

您可以更显着地更改这一点,以允许类“注册”以便能够为Output类本身中的特定“输出机制”进行写入。你可以做Output一个单例(有反对这样做的论据,但它会比为此目的在你的主程序中粘贴公共静态变量更好)。这是一个对您的原始课程进行更重大更改的示例:

public sealed class Output
{
    private Dictionary<Out, Action<string, Color>> registeredWriters = new Dictionary<Out, Action<string, Color>>();

    public static readonly Output Instance = new Output();

    private void Output() { } // Empty private constructor so another instance cannot be created.

    public void Unregister(Out outType)
    {
        if (registeredWriters.ContainsKey(outType))
            registeredWriters.Remove(outType);
    }

    // Assumes caller will not combine the flags for outType here
    public void Register(Out outType, Action<string, Color> writer)
    {
        if (writer == null)
            throw new ArgumentNullException("writer");

        if (registeredWriters.ContainsKey(outType))
        {
            // You could throw an exception, such as InvalidOperationException if you don't want to 
            // allow a different writer assigned once one has already been.
            registeredWriters[outType] = writer;
        }
        else
        {
            registeredWriters.Add(outType, writer);
        }
    }

    public void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
    {
        bool includeDebug = false;
        #if DEBUG
        includeDebug = true;
        #endif

        foreach (var outType in registeredWriters.Keys)
        {
            if (outType == Const.Out.Debug && !includeDebug)
                continue;

            if (bitmask(output, outType))
                registeredWriters[outType](str, color);
        }
    }
}

然后在你的程序的其他地方,比如在表单类中,注册一个作家,做:

Output.Instance.Register(Const.Out.Main, (s, c) => this.Box.WriteLine(s, c));

卸载表单后,您可以执行以下操作:

Output.Instance.Unregister(Const.Out.Main);

然后另一种方法是不使用单例。然后,您可以拥有多个Output用于不同目的的实例,然后将它们注入到您的其他类中。例如,更改主窗体的构造函数以接受Output参数并将 this 存储为对象变量以供以后使用。然后主窗体可以将其传递给也需要它的子窗体。

于 2013-07-18T18:17:16.443 回答
0

如果您的具有需要写入数据的对象的行为如下:

A 总是写到控制台和日志 B 总是写到日志 C 总是写到控制台

对于所有数据,最好的办法是声明一个接口并让它们中的每一个实现输出的接口方法。然后,在您的调用代码中,将它们声明为它们的实际类型,而不是类型 IOutput 或您调用的具有该方法的任何接口。然后有两种辅助方法,一种用于实际输出到控制台,一种用于实际输出到日志文件。A 会调用两个助手,B 和 C 是他们各自的助手。

另一方面,如果您的对象将在不同时间写入各种日志:

A、B 和 C 有时会写入控制台,有时会写入日志,具体取决于某些属性

然后,我建议您创建一个事件处理程序,用于当一个类想要编写某些东西时。然后,有逻辑来识别写入控制台的内容以及写入侦听器类的内容并将适当的内容附加到该输出事件。这样,您可以将关于写入内容的逻辑保留在仅封装该功能的类中,同时使 A、B 和 C 类免于可能会困扰您的依赖关系。正如您所描述的那样,考虑使用一个使用位掩码的整体方法。一旦 A、B 或 C 的日志记录行为发生变化,或者如果您需要添加新的输出,您突然需要担心一个类或方法会同时影响所有它们。这使得它的可维护性降低,并且测试错误也更棘手。

于 2013-07-18T14:34:17.237 回答
0
MethodInfo methodname = typeof(object).GetMethod("MethodA");

然后只需使用 if 语句来检查 methodname 是否为空。

于 2013-07-18T14:35:31.080 回答