简体   繁体   English

如何使用C#在Main方法中初始化需要的类之前

[英]How to initialize class before it is needed in the Main method using C#

Given this code: 给出以下代码:

using System;
using System.Collections.Generic;
using FactoryCallback = System.Func<System.Object>;

interface IMessageProvider
{
    string Message { get; }
}

class MessageProvider : IMessageProvider
{
    private Random generator = new Random();

    public static void Register()
    {
        InstanceFactory.Register(typeof(IMessageProvider), () => new MessageProvider());
    }

    public string Message
    {
        get
        {
            switch (generator.Next(3))
            {
                case 0:
                    return "No matter where you go, there you are.";
                case 1:
                    return "Once I thought I'd made a mistake, but I was wrong.";
                case 2:
                    return "I used to think I was indecisive; now I'm not so sure";
                default:
                    throw new IndexOutOfRangeException();
            }
        }
    }
}

class InstanceFactory
{
    private static Dictionary<Type, FactoryCallback> typeCallbacks =
        new Dictionary<Type, FactoryCallback>();

    public static void Register(Type type, FactoryCallback callback)
    {
        typeCallbacks.Add(type, callback);
    }

    public static Object InstanceOf(Type type)
    {
        return typeCallbacks[type]();
    }
}

public class RandomMessage
{
    public static void Main()
    {
        IMessageProvider provider =
            InstanceFactory.InstanceOf(typeof(IMessageProvider)) as IMessageProvider;
        Console.WriteLine(String.Format("The message is:\n{0}", provider.Message));
    }
}

This program will not run successfully as is because the MessageProvider never actually registers with the InstanceFactory. 该程序将无法按原样成功运行,因为MessageProvider从未实际向InstanceFactory注册。 Obviously, a call to MessageProvider.Register could be added to the beginning of RandomMessage.Main. 显然,可以将对MessageProvider.Register的调用添加到RandomMessage.Main的开头。 However, that now requires RandomMessage to have knowledge of MessageProvider and defeats the whole purpose of the InstanceFactory class which is intended to separate how to create something from what that something does. 但是,这现在需要RandomMessage具备MessageProvider的知识,并且无法实现InstanceFactory类的全部目的,该类旨在将创建方法与执行操作分开。 I would like the MessageProvider to be able to automatically register with the InstanceFactory before RandomMessage.Main tries to create an IMessageProvider instance. 我希望MessageProvider能够在RandomMessage.Main尝试创建IMessageProvider实例之前自动向InstanceFactory注册。 How could this be accomplished? 如何做到这一点?

The registration of service IMessageProvider and component MessageProvider with InstanceFactory is not the responsbility of the MessageProvider implementation, it is an infrastructure concern for the application, therefore should be done inside of the Main method. 服务IMessageProvider和组件MessageProviderInstanceFactory上的注册不是MessageProvider实现的责任,它是应用程序的基础结构问题,因此应在Main方法内部完成。

public class RandomMessage
{
    public static void Main()
    {
        // Register services with InstanceFactory at the start of Main method
        InstanceFactory.Register(typeof(IMessageProvider), () => new MessageProvider());

        IMessageProvider provider = InstanceFactory.InstanceOf(typeof(IMessageProvider)) as IMessageProvider;
        Console.WriteLine(String.Format("The message is:\n{0}", provider.Message));
    }
}

If you somehow referenced MessageProvider before calling InstanceFactory.InstanceOf() , you could just add a static constructor to MessageProvider class: 如果您在调用InstanceFactory.InstanceOf()之前以某种方式引用了MessageProvider ,则可以将静态构造函数添加到MessageProvider类中:

static MessageProvider()
{
    Register();
}

If it's not an option, you can do it via reflection by adding a custom attribute to all classes you want to register and calling Register() for all of them in static constructor of InstanceFactory like described here . 如果它不是一个选项,你可以通过添加通过反射做自定义属性您要注册的所有类和调用Register()为所有这些在静态构造函数InstanceFactory像描述在这里

Consider using some Inversion of Control library. 考虑使用一些Inversion of Control库。 like Unity (but it might be overkill) or SimpleContainer. 像Unity(但可能会过大)或SimpleContainer。

Then you will 'Register' instance of interfaces while your app start (in examples you should have file like 'bootstrapper.cs' ) 然后,您将在应用启动时“注册”接口实例(在示例中,您应具有“ bootstrapper.cs”之类的文件)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM