Description
Details about Problem
Target: any
Firmware image version: newest
Worked before? If so, with which nanoFramework image version: I checked the stable version and it also doesn't work
Device capabilities output:
Description
I have created a library that I am going to manually load during runtime with Assemby.Load. In the library I have classes that have static fields and static constructors. Fields are not automatically initialized and constructors are not called when assembly is loaded or before first use.
Detailed repro steps so we can see the same problem
- Create simple library with static fields and static constructor for example something like this
public class MyClass
{
private static int[] storage = new int[8]; //this static field isn't initialized
// this static constructor isn't called automatically
static MyClass()
{
storage = new int[16];
}
public static void Store(int position, int value)
{
if (storage == null || position < 0 || position >= storage.Length)
return;
storage[position] = value;
}
public static int Load(int position)
{
if (storage == null || position < 0 || position >= storage.Length)
return int.MinValue;
return storage[position];
}
}
- Wrie program that load assembly and try to run methods:
using System.Device.Gpio;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
namespace Program
{
public class Program
{
private static GpioController s_GpioController;
public static void Main()
{
s_GpioController = new GpioController();
GpioPin led = s_GpioController.OpenPin(13, PinMode.Output);
led.Write(PinValue.High);
Debug.WriteLine("Hello from nanoFramework!");
// array below is a pe file from this code:
//public class MyClass
//{
// private static int[] storage = new int[8]; //this static field isn't initialized
// // this static constructor isn't called automatically
// static MyClass()
// {
// storage = new int[16];
// }
// public static void Store(int position, int value)
// {
// if (storage == null || position < 0 || position >= storage.Length)
// return;
// storage[position] = value;
// }
// public static int Load(int position)
// {
// if (storage == null || position < 0 || position >= storage.Length)
// return int.MinValue;
// return storage[position];
// }
//}
byte[] myLib_pe = {
0x4E, 0x46, 0x4D, 0x52, 0x4B, 0x31, 0x00, 0x00, 0x6C, 0x77, 0x97, 0xD8,
0xA5, 0x2E, 0xBA, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
0x98, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00,
0xB8, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00,
0xA0, 0x01, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x01, 0x02, 0x00, 0x00, 0xD2, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00,
0x03, 0x00, 0x00, 0x00, 0xB1, 0xFE, 0x40, 0xFE, 0x00, 0x00, 0x00, 0x00,
0xF7, 0xFE, 0x40, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x03, 0x11, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x15, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x11, 0x00,
0xFE, 0xFF, 0x00, 0x00, 0x86, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0x00, 0x91, 0x24, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x06, 0x00, 0x0F, 0x00, 0x17, 0x00,
0x96, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x0E, 0x00, 0x09, 0x00,
0xDD, 0xFE, 0x3C, 0x00, 0x96, 0x00, 0x00, 0x00, 0x07, 0x01, 0x02, 0x02,
0x10, 0x00, 0x0F, 0x00, 0x00, 0x4D, 0x79, 0x4C, 0x69, 0x62, 0x00, 0x4D,
0x79, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x00, 0x53, 0x74, 0x6F, 0x72, 0x65,
0x00, 0x73, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x06, 0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x07, 0x07, 0x01, 0x00, 0x01, 0x07, 0x07, 0x00, 0x02, 0x28, 0x00, 0x80,
0x00, 0x2A, 0x1E, 0x8D, 0x01, 0x40, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x10,
0x8D, 0x01, 0x40, 0x80, 0x00, 0x00, 0x2A, 0x00, 0x7E, 0x00, 0x00, 0x2C,
0x11, 0x02, 0x16, 0x32, 0x0D, 0x02, 0x7E, 0x00, 0x00, 0x8E, 0x69, 0xFE,
0x04, 0x16, 0xFE, 0x01, 0x2B, 0x01, 0x17, 0x0A, 0x06, 0x2C, 0x02, 0x2B,
0x06, 0x7E, 0x00, 0x00, 0x02, 0x03, 0x9E, 0x2A, 0x00, 0x7E, 0x00, 0x00,
0x2C, 0x11, 0x02, 0x16, 0x32, 0x0D, 0x02, 0x7E, 0x00, 0x00, 0x8E, 0x69,
0xFE, 0x04, 0x16, 0xFE, 0x01, 0x2B, 0x01, 0x17, 0x0A, 0x06, 0x2C, 0x08,
0x20, 0x00, 0x00, 0x00, 0x80, 0x0B, 0x2B, 0x08, 0x7E, 0x00, 0x00, 0x02,
0x94, 0x0B, 0x2B, 0x00, 0x07, 0x2A, 0x00, 0x00
};
var loadedAssembly = Assembly.Load(myLib_pe);
if (loadedAssembly != null)
{
var type = loadedAssembly.GetTypes()[0];
var storeMethod = type.GetMethod("Store");
var loadMethod = type.GetMethod("Load");
if (storeMethod != null)
{
//store 5 at position 2
storeMethod.Invoke(null, new object[] { 2, 5 });
//load value form second position
int value = (int)loadMethod.Invoke(null, new object[] { 2 });
//if value is int.MinValue then infinite fast blinking
if (value == int.MinValue)
{
for (; ; )
{
led.Write(PinValue.Low);
Thread.Sleep(25);
led.Write(PinValue.High);
Thread.Sleep(25);
}
}
// if value is positive blink correct number times
while (value-- > 0)
{
led.Write(PinValue.Low);
Thread.Sleep(250);
led.Write(PinValue.High);
Thread.Sleep(250);
}
}
}
Thread.Sleep(Timeout.Infinite);
}
}
}
...
Expected behaviour
Static constructor should be called and field initialized before first usage.
Additional context
If library is referenced (not loaded during runtime) then everything seems to work correctly.