1

Is it possible to create a list or array of pointers in C#?

I want to have a list of T* rather than use IntPtr because i am forever having to type Marshal Ptr To Structure methods all over the place rather than directly access methods via -> command.

I tried making a list with T* but it says it cannot use it as a type. So is my only option to just constantly convert when needed from the IntPtr ?

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
WDUK
  • 1,412
  • 1
  • 12
  • 29
  • 1
    Not sure if I have understood, but https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/unsafe-code – Steve May 06 '22 at 08:12
  • Why not have a collection/list/array of typed, managed, safe types, instead of pointers? – Jodrell May 06 '22 at 08:13
  • Why are you asking this? C# isn't C++. Unless you want to interop with unmanaged code, there's seldom any reason to use pointers - reference types already work with pointers to the objects (that's why they're called reference types). And if you want to use pointers to struct *don't use struct in the first place*. – Panagiotis Kanavos May 06 '22 at 08:15
  • I think some more detailed description of your problem would be useful. You would typically try to keep the unmanaged/managed layer as small and dumb as possible, so I'm not sure doing anything fancy with pointers on the managed side is a great idea. – JonasH May 06 '22 at 08:16
  • ` via -> command` there's no such command because it's not needed. When you use `someString.Length`, the `someString` variable holds a reference to the actual `string` object. `someString.Length` is the equivalent of C++'s `someSmartString->length();` – Panagiotis Kanavos May 06 '22 at 08:17
  • @Jodrell can't - am doing data orientated design, so no managed objects can be used. Has to be all structs to take advantage of the compiler being used. – WDUK May 06 '22 at 08:17
  • 1
    @WDUK, then why use c#? I don't think that a data orientated design precludes the use of managed types. https://stackoverflow.com/questions/1641580/what-is-data-oriented-design – Jodrell May 06 '22 at 08:18
  • @WDUK that phrase makes no sense at all. Why would data processing have problems with managed objects? Aren't DataTable managed objects? What about DataFrame in ML.NET and all the other ML classes? – Panagiotis Kanavos May 06 '22 at 08:18
  • @Jodrell because Unity uses C# – WDUK May 06 '22 at 08:18
  • @Steve yeah you see where they have `Node*` etc. I want to be able to do `List` but it won't allow it. I have to use IntPtr wrapper which is annoying. – WDUK May 06 '22 at 08:19
  • 1
    @WDUK Unity changes things *completely*. Perhaps you should rewrite the question to actually ask what you want, including the *most important* information - this is Unitye, ie JVM, not just C# – Panagiotis Kanavos May 06 '22 at 08:19
  • @PanagiotisKanavos i'm not sure what you're referring to with DataFrame etc. And strings are managed types in C# - i'm not using them. I just want a collection of my pointers rather than use IntPtr. – WDUK May 06 '22 at 08:19
  • 1
    @WDUK I repeat. Post a new question explaining the actual problem and saying you use Unity *at the very beginning*. Your question makes no sense otherwise. As in no sense to someone working on data processing with .NET for 17 years. Unity isn't .NET, it's C# over JVM – Panagiotis Kanavos May 06 '22 at 08:21
  • The question is simple, in general is it possible to have a collection, i.e a list, array, hashset etc of `int*` for example without using `IntPtr` forget the reasons for why I might be doing it. It's a C# question and not engine related. – WDUK May 06 '22 at 08:22
  • 1
    @WDUK if it was simple you wouldn't have so many people asking what you mean. People rarely use int pointers, unless forced by interop with the environment. I also suspect this isn't even the actual problem but the assumed solution. C# 7 added [ref structs like Span](https://learn.microsoft.com/en-us/dotnet/api/system.span-1?view=net-6.0) that remove the need of passing pointers to value types. Unity supports Span since [2021.2](https://docs.unity3d.com/2021.2/Documentation/Manual/UpgradeGuide20212.html). Your actual problem could be solved using `Span` – Panagiotis Kanavos May 06 '22 at 08:38
  • Well i'll ask a new question when I get home then. I assumed it would be common when using structs. Since i have a graph of nodes and currently the graph has a List of `IntPtr` which is all the pointers to the nodes. It won't let me use `Node*` for the generic type. – WDUK May 06 '22 at 08:41
  • "data orientated design" does not require native code, it is perfectly possible to layout your data in managed data structures however you want. There is also support for ref-returns and other features to avoid the need for copies when using value types. There is also a significant risk that you are just de-optimizing due to the overhead of marshalling objects. Always measure before trying to optimize. – JonasH May 06 '22 at 09:09
  • @JonasH the compiler will not accept any kind've reference type. And thats besides the point of the question anyway. – WDUK May 06 '22 at 09:15
  • I think the bigger question is why do you want to use `IntPtr` in the first place. Depending on what it is you are trying to do, the last thing you want to do is to perform unnecessary conversion `in a game` –  May 06 '22 at 09:36
  • @WDUK _"because Unity uses C#"_ - and **so are you** by the simple fact that you are using `IntPtr`, `Marshal` and other other C# code you have written –  May 06 '22 at 09:38
  • @MickyD it was the only thing that I could think of to add to a collection since i could not use `Type*` – WDUK May 06 '22 at 09:39
  • @MickyD yes i know i am using C# - i was asked why I was using C# to start with. My answer is because unity uses it so i am required to use it... – WDUK May 06 '22 at 09:39
  • What compiler? And why would you need to use reference types? I have still not seen any good reason for using unmanaged code, nor a reason not to keep the data in managed memory. This is starting to sound more and more like a [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – JonasH May 06 '22 at 09:42
  • @JonasH There is no XY problem unity's burst compiler does not allow reference types. its a data orientated design not object orientated design so no classes can be used. All data must be in structs. But i need persistent data in arrays because copying values causes problems with linking data together over time. `And why would you need to use reference types`.. if i was i wouldn't need pointers since ref types do the job for me. – WDUK May 06 '22 at 09:44
  • @WDUK _"The question is simple, in general is it possible to have a collection, i.e a list, array, hashset etc of int* for example without using IntPtr"_ - this is all moot anyway. You do realise that the language you pick to develop a Unity isn't the final language that Unity uses to produce the final executable for a _particular platform_. Prior to WASM, that Unity C# code you wrote will run in the web browser as **JavaScript**. Even today, C# will be cross-compiled to something XCode prefers for Mac devs –  May 06 '22 at 09:50
  • I have no idea what you're on about or the relevancy @MickyD unity uses c#8 for scripting projects i'm not going to be writing in javascript for the project so the question really is just applicable to C# and not really unity related. – WDUK May 06 '22 at 09:52
  • @PanagiotisKanavos `Unity isn't .NET, it's C# over JVM ` pretty sure unity does use .Net standard 2.1 so not sure what you mean by that. And supports .net 4 aswell. – WDUK May 06 '22 at 09:55
  • So, what is stopping you from using managed arrays of structs? or structs of arrays if that is your preference. – JonasH May 06 '22 at 09:55
  • @JonasH thats fine but i need to be referring to the actual struct in the array not a copy of it. So i would rather an array of pointers to structs, so that if the array resizes my pointers are still pointing to the struct. – WDUK May 06 '22 at 09:57
  • By the way, there's always Unity _[Native plug-ins](https://docs.unity3d.com/Manual/NativePlugins.html)_. Plugins are pre-compiled DLLs created externally to Unity and placed in the **Assets\Plugins** folder. The plugin is a simple DLL that you can make effortlessly via a Visual Studio c/c++ DLL wizard. If you do this then you never have to worry about `IntPtr` this `Marshal` that - just do everything native. No conversion. Depending on exactly you are trying to do, the only C# surface will be invoking that external c/c++ function. –  May 06 '22 at 09:57
  • @WDUK _"so the question really is just applicable to C# and not really unity related"_ - then why mention Unity yourself and tag your question `unity3d`? Oh I guess we can ignore the questions title of _"`In Unity`, how do you create a collection of pointers?"_ –  May 06 '22 at 10:04
  • That really sounds even more like an XY problem. In most cases you should be able to use indices to access you objects when needed. If you need persistent pointers you open up a whole new can of worms, and that does not sound very "data oriented". If you operate under some special restrictions you really need to specify these in the question. – JonasH May 06 '22 at 10:05
  • This is clearly an XY problem. I think if you 1) knew how `c` worked 2) and C# and 3) Unity this wouldn't be a problem. Plus your approach is flawed. Use native plugins and be done with it –  May 06 '22 at 10:07
  • @JonasH I'm aware of the can of worms. My code works currently I never suggested I didn't know what I was doing. But I'm currently storing Type* as Intptr in my list, but this means I'm constantly using marshal function of ptr to structure. It would have been nice to directly store Type* so I don't have to convert all of the time when using my list. Unity does not offer smart pointers like unreal does for c++ so I don't have that luxury at the moment. – WDUK May 06 '22 at 10:31

1 Answers1

2
  1. You can declare an array of pointer.

    unsafe Vector3*[] vectorPointerArray;
    
  2. You cannot use pointer as a generic type parameter like List<Vector3*>, this is still under consideration.

  3. Because of the feasibility 1, you can create a collection to hold pointers, though it cannot implement generic interfaces like IList<T>.

    unsafe class UnsafePointerList<T> where T : unmanaged
    {
        private T*[] _items;
        public T* this[int index] => _items[index];
    }
    
    UnsafePointerList<Vector3> vectorPointerList;
    var x = vectorPointerList[0]->x;
    
shingo
  • 18,436
  • 5
  • 23
  • 42
  • If you passed data by pointer then wanted to add it would this create a copy `unsafeList.Add(*myVector3);` so I first go from type `Vector*` to type `Vector3` and then add it? Or would that no longer be the same pointer as the one i passed in? – WDUK May 06 '22 at 09:37
  • Sorry I can't understand your comment. Do you want to add a pointer or an instance? What does `unsafeList.Add(*myVector3);` mean? What's the type of `myVector3`? – shingo May 06 '22 at 09:43
  • basically i have the function `void Add(in Node* node) => _unsafeList.Add(*node)` would this be the same pointer as the one i passed in. Or would i lose the connection to it in the list as it would be a new pointer ? I don't want to lose the original pointer. – WDUK May 06 '22 at 09:46
  • It would be a new pointer if you do that. – shingo May 06 '22 at 09:48
  • Yeah thats what i am trying to avoid ! I need to add specifically the `Node*` pointer i passed in. Is that possible? – WDUK May 06 '22 at 09:48
  • You should write the method like this: `void Add(T* item) => _items[_p++] = item;` – shingo May 06 '22 at 09:52
  • So this now becomes the pointer of the element in the list? So what happens if the list resizes ? The pointer is no longer valid... – WDUK May 06 '22 at 09:53
  • What you want is _"a list or array of pointers"_, is it? A pointer is just an address, so `T*[]` is almost same as `long[]`, if you don't change it, it keeps the same value. Whether it's valid or not depends on how you use it. – shingo May 06 '22 at 10:02
  • What I want is to add a specific pointer I have already created such as Node* to my list not create a new one when I add it to my list because then I lose the reference if I resize the array for example which is bad, it's a subtle difference. – WDUK May 06 '22 at 10:34
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/244539/discussion-between-shingo-and-wduk). – shingo May 06 '22 at 11:11