Closed dotlogix closed 4 months ago
The classic "DynamicMethod" way works perfectly fine so the field name is definetly correct:
Func<List<int>, int[]> lambda;
{
var list = Expression.Parameter(typeof(List<int>));
var array = Expression.Field(list, typeof(List<int>).GetField("_items", BindingFlags.Instance | BindingFlags.NonPublic)!);
lambda = Expression.Lambda<Func<List<int>, int[]>>(array, list).Compile();
}
{
var list = new List<int> { 1, 2, 3, 4, 5, 6 };
Console.WriteLine(string.Join(", ", lambda(list)));
}
Thanks for the kind words! 🙂
Which framework are you targeting? I suppose it's .NET ("Core") or .NET Standard, which would mean you're not compiling against the actual implementation assembly, but a reference assembly which only contains the public API surface. That's why InlineIL can't find the implementation details such as private fields.
The DynamicMethod approach works since you have access to the implementation at that point.
You'd have to reference System.Private.CoreLib, but that brings its own problems. You may want to take a look at #31 though.
BTW, if you want to access the underlying array of a list, maybe CollectionsMarshal.AsSpan(list)
could suffice (you get a span, not an array though).
If you really need the array, code such as this should do the job, but it's not pretty:
private static T[] GetListArray<T>(List<T> list)
=> Unsafe.As<ListLayout<T>>(list).Items;
private class ListLayout<T>
{
public T[] Items = [];
#pragma warning disable CS0169 // Field is never used
private int _size;
private int _version;
#if NETFRAMEWORK
private object? _syncRoot;
#endif
#pragma warning restore CS0169 // Field is never used
}
Thx for your work this is helpful indeed. Basically what I need is sth like this:
ref var arrayRef = ref MemoryMarshal.GetArrayDataReference(list._items);
It is used in a very high-performance ECS. Basically all code I use there is not "pretty" so this fit's perfectly fine. Still better than the whole type erasure unmanaged pointer stuff I have to do :D
I close this as completed with this response.
If that's all you need then isn't this better:
ref var arrayRef = ref MemoryMarshal.GetReference(CollectionsMarshal.AsSpan(list));
Just FYI, the _version
field has a good chance of being removed soon, and then bad things could happen.
Hey there thx for your awesome work.
I tried to use your extension however it seems I am missing sth or there is a bug potentially. I have this code:
However I get this error when I try to build:
I tried to do the same with a class defined in my own assembly and this worked perfectly fine. Not sure what I am missing could you assist maybe?