使用 Activator.CreateInstance() 创建的对象不会等待整个对象在 Release 上初始化

Posted

技术标签:

【中文标题】使用 Activator.CreateInstance() 创建的对象不会等待整个对象在 Release 上初始化【英文标题】:Objects created with Activator.CreateInstance() do not wait for the entire object to be initialized on Release 【发布时间】:2021-03-23 13:39:19 【问题描述】:

我的主项目加载带有设备的库并为它们创建实例。在Debug模式下发布后,项目工作正常,在Release模式下发布时出现问题。我不知道为什么,但它不会等待它创建的对象初始化。

这是一个代码sn-p:

try

    AssemblyName name = AssemblyName.GetAssemblyName(module);
    Type[] iLoadTypes = (from t in Assembly.Load(name).GetExportedTypes()
                         where !t.IsInterface && !t.IsAbstract
                         where typeof(IDevice).IsAssignableFrom(t)
                         select t).ToArray();
    if (iLoadTypes.Length > 0)
    
        IDevice[] instantiatedDevices =
            iLoadTypes.Select(t => (IDevice)Activator.CreateInstance(t)).ToArray();
        foreach (var device in instantiatedDevices)
        
            Devices.Add(device);
        
    
    iLoadTypes = (from t in Assembly.Load(name).GetExportedTypes()
                  where !t.IsInterface && !t.IsAbstract
                  where typeof(IDeviceToolProvider).IsAssignableFrom(t)
                  select t).ToArray();
    IDeviceToolProvider[] instantiatedProviders =
        iLoadTypes.Select(t => (IDeviceToolProvider)Activator.CreateInstance(t)).ToArray();
    foreach (var provider in instantiatedProviders)
    
        var device = Devices.Find(dev => dev.GetType() == provider.DeviceType);
        if (device == null)
            continue;
        provider.Device = device;
        if (!DeviceToolProviders.ContainsKey(device))
            DeviceToolProviders[device] = new List<IDeviceToolProvider>();
        DeviceToolProviders[device].Add(provider);
        provider.Initialize();
    

catch (Exception ex)


以及创建的对象之一:

public class WZWCDeviceTesterToolProvider : IDeviceToolProvider

    internal static readonly UserSettingEntry<ConnectionDescriptorBuilder> ConnectorDescriptorBuilderEntry =
        UserSettingEntry.Register("ConnectorDescriptorBuilderEntry", typeof(WZWCDeviceTesterToolProvider),
            new UserSettingEntryMetadata<ConnectionDescriptorBuilder>());

    public string Name  get  return "WZW";   

    ...   
    public void Initialize()
    

    

它没有等待属性ConnectorDescriptorBuilderEntry。我做了一个测试并将这个初始化添加到 Initialize() 方法中,但它也没有在那里初始化。它只会在一段时间后发生。

我不知道是怎么做到的,但它之前是有效的,我从别人那里接手了这个项目。我没有更改主项目中的任何内容。我刚刚添加了一个新设备。它在初始化期间不会抛出任何错误。它最终会初始化所有内容。这里没有异步。

净 4.5

我不知道发布的代码量是否足以解决我的问题,但也许有人可以告诉我在哪里寻找解决方案以及为什么它适用于 Debug 而不是 Release?

【问题讨论】:

在没有静态构造函数的情况下,只保证静态字段ConnectorDescriptorBuilderEntry在第一次使用前被初始化。见***.com/questions/710793/… @KlausGütter 不幸的是我不知道为什么没有调用 Register() 方法;当我尝试调试它时(当它在方法 Initialize() 中初始化时),它在使用程序一段时间后运行。 尝试将初始化移动到静态构造函数static WZWCDeviceTesterToolProvider() ConnectorDescriptorBuilderEntry = ... @KlausGütter 由于我的英语不是最好的,我第一次听不懂你,但你是对的,你的回答解决了我的问题。 【参考方案1】:

根据C# specification,如果没有静态构造函数,则无法保证静态字段何时被精确初始化,只能在第一次使用之前发生。

15.5.6.2 静态字段初始化

类的静态字段变量初始化器对应于 以文本顺序执行的任务序列 它们出现在类声明中(§15.5.6.1)。在一个 部分类,“文本顺序”的含义由 §15.5.6.1。如果类中存在静态构造函数(第 15.12 节), 静态字段初始化器的执行发生在紧接之前 执行该静态构造函数。 否则,静态字段 初始化器在依赖于实现的时间执行 第一次使用该类的静态字段

但是,如果有静态构造函数,则保证所有静态字段在运行之前都已初始化,这反过来又保证在您实例化类的对象或第一次访问静态成员时发生。

所以要强制初始化你的字段,你可以添加一个静态构造函数:

static WZWCDeviceTesterToolProvider()


【讨论】:

以上是关于使用 Activator.CreateInstance() 创建的对象不会等待整个对象在 Release 上初始化的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)