Skip to content

Commit af1a04e

Browse files
Complete examples in custom marshalling generation walkthrough (#46272)
1 parent 91cd8aa commit af1a04e

File tree

1 file changed

+31
-13
lines changed

1 file changed

+31
-13
lines changed

docs/standard/native-interop/custom-marshalling-source-generation.md

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,34 @@ public struct Example
4545
}
4646
```
4747

48-
`ExampleMarshaller`, the entry-point marshaller type, is marked with <xref:System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute>, pointing at a [marshaller implementation](#marshaller-implementation) type. In this example, `ExampleMarshaller` is both the entry point and the implementation. It conforms to [marshaller shapes][value_shapes] expected for custom marshalling of a value.
48+
`ExampleMarshaller`, the entry-point marshaller type, is marked with <xref:System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute>, pointing at a [marshaller implementation](#marshaller-implementation) type. In this example, `ExampleMarshaller` is both the entry point and the implementation. It conforms to [marshaller shapes][value_shapes] expected for custom marshalling of a value. Note that `ExampleMarshaller` assumes UTF-8 string encoding.
4949

5050
```csharp
5151
[CustomMarshaller(typeof(Example), MarshalMode.Default, typeof(ExampleMarshaller))]
52-
internal static class ExampleMarshaller
52+
internal static unsafe class ExampleMarshaller
5353
{
5454
public static ExampleUnmanaged ConvertToUnmanaged(Example managed)
55-
=> throw new NotImplementedException();
55+
{
56+
return new ExampleUnmanaged()
57+
{
58+
Message = (IntPtr)Utf8StringMarshaller.ConvertToUnmanaged(managed.Message),
59+
Flags = managed.Flags
60+
};
61+
}
5662

5763
public static Example ConvertToManaged(ExampleUnmanaged unmanaged)
58-
=> throw new NotImplementedException();
64+
{
65+
return new Example()
66+
{
67+
Message = Utf8StringMarshaller.ConvertToManaged((byte*)unmanaged.Message),
68+
Flags = unmanaged.Flags
69+
};
70+
}
5971

6072
public static void Free(ExampleUnmanaged unmanaged)
61-
=> throw new NotImplementedException();
73+
{
74+
Utf8StringMarshaller.Free((byte*)unmanaged.Message);
75+
}
6276

6377
internal struct ExampleUnmanaged
6478
{
@@ -89,33 +103,37 @@ internal static partial Example ConvertExample(Example example);
89103

90104
Apply the <xref:System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshallerAttribute> to a marshaller entry-point type to indicate that it's for contiguous collections. The type must have one more type parameter than the associated managed type. The last type parameter is a placeholder and will be filled in by the source generator with the unmanaged type for the collection's element type.
91105

92-
For example, you can specify custom marshalling for a <xref:System.Collections.Generic.List%601>. In the following code, `ListMarshaller` is both the entry point and the implementation. It conforms to [marshaller shapes][collection_shapes] expected for custom marshalling of a collection.
106+
For example, you can specify custom marshalling for a <xref:System.Collections.Generic.List%601>. In the following code, `ListMarshaller` is both the entry point and the implementation. It conforms to [marshaller shapes][collection_shapes] expected for custom marshalling of a collection. Note that it is an incomplete example.
93107

94108
```csharp
95109
[ContiguousCollectionMarshaller]
96110
[CustomMarshaller(typeof(List<>), MarshalMode.Default, typeof(ListMarshaller<,>))]
97111
public unsafe static class ListMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
98112
{
99113
public static byte* AllocateContainerForUnmanagedElements(List<T> managed, out int numElements)
100-
=> throw new NotImplementedException();
114+
{
115+
numElements = managed.Count;
116+
nuint collectionSizeInBytes = managed.Count * /* size of T */;
117+
return (byte*)NativeMemory.Alloc(collectionSizeInBytes);
118+
}
101119

102120
public static ReadOnlySpan<T> GetManagedValuesSource(List<T> managed)
103-
=> throw new NotImplementedException();
121+
=> CollectionsMarshal.AsSpan(managed);
104122

105123
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(byte* unmanaged, int numElements)
106-
=> throw new NotImplementedException();
124+
=> new Span<TUnmanagedElement>((TUnmanagedElement*)unmanaged, numElements);
107125

108126
public static List<T> AllocateContainerForManagedElements(byte* unmanaged, int length)
109-
=> throw new NotImplementedException();
127+
=> new List<T>(length);
110128

111129
public static Span<T> GetManagedValuesDestination(List<T> managed)
112-
=> throw new NotImplementedException();
130+
=> CollectionsMarshal.AsSpan(managed);
113131

114132
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(byte* nativeValue, int numElements)
115-
=> throw new NotImplementedException();
133+
=> new ReadOnlySpan<TUnmanagedElement>((TUnmanagedElement*)nativeValue, numElements);
116134

117135
public static void Free(byte* unmanaged)
118-
=> throw new NotImplementedException();
136+
=> NativeMemory.Free(unmanaged);
119137
}
120138
```
121139

0 commit comments

Comments
 (0)