C#如何判断对象是否实现了特定方法

时间:2013-07-18 14:24:39

标签: c# class object methods console

所以我有许多不同的潜在对象可以输出数据(字符串)。我想要做的是运行一个通用的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,并将它们转换为适用于多个基本类型的对象。假设我可以让Console在这个方案中正常工作,这将是一个明显的问题,它不是与实际Box相同的基本类型,但是,如果我有一些不是Box的东西,那么它会很可爱

    之类的东西

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

  3. 所以我不必单独施放它们。

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

    编辑:我意识到如果你知道如何避免它,那么向Program添加公共属性是一个坏主意(需要能够从任何地方访问任何来来往往的WriteLine-able表单对象) ),请务必详细说明。

3 个答案:

答案 0 :(得分: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参数并存储这是一个对象变量供以后使用。然后,主要表单可以将其传递给也需要它的子表单。

答案 1 :(得分:0)

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

总是写入控制台和日志 B总是写入日志 C总是写入控制台

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

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

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

然后我建议你为一个类想要写一些东西时创建一个事件处理程序。然后,具有识别写入控制台的内容以及写入侦听器类中的内容以及将适当的内容附加到该输出事件的逻辑。这样,您可以保留关于正在编写的内容的逻辑,这些类只包含该功能,同时使A,B和C类没有依赖性,可能会让您感到困惑。考虑使用您描述的使用位掩码的单片方法。一旦A,B或C的日志记录的行为发生变化,或者您需要添加新输出,您就会突然担心一个类或方法会立即影响所有这些。这使得它的可维护性降低,并且测试bug也更加棘手。

答案 2 :(得分:0)

MethodInfo methodname = typeof(object).GetMethod("MethodA");

然后只使用if语句检查methodname是否为null。