Closed monkey0506 closed 1 month ago
Actually, because the MarshalAsAttribute
s can now only be supplied by the marshaller type, this can be done more simply by checking the typeof
the marshaller. Handling the CallingConvention
is already a supported case if it is not a static value.
Fixed by #36.
Describe the issue
Open generic interceptors compare the interface generic type arguments to select an appropriate implementation class, but do not compare any marshalling behaviors (except when there is no static calling convention). This issue does not apply to closed generic interceptors, because they are guaranteed to have the same marshalling for every intercepted method.
Here,
TMarshaller
is a generic type parameter of some containing type or method, constrained bywhere TMarshaller : IMarshaller<TMarshaller>, new()
. For example, if this line was contained in a method such as:And then this method was invoked by
GetNativeAction<CdeclMarshaller>(functionPtr)
andGetNativeAction<StdCallMarshaller>(functionPtr)
, then we will generate an interceptor that performs checks like:We have distinct implementation classes for each marshaller, but because the interface type arguments are the same, the second branch of our interceptor will always be unreachable.
We cannot split this into separate interceptors, because the two calls refer to a single line in the source (inside the body of
GetNativeAction
).Proposed solution
Given this example it may seem that the solution is to carry the generic type argument for marshaller, so we can perform a similar
Type
check. Rather, this approach would still fail if the marshaller is not supplied at all (by the non-generic factory methods), yet the marshalling behaviors are the same.Here, we must perform runtime checks of the marshalling behaviors. This was previously done in the
incremental-generator
branch by caching an equatable representation of theMarshalAsAttribute
s so that the factory methods were not recreating these objects every time. We can take the same approach here.When creating the open generic interceptor source text, we have a collection of
ImplementationClass
es, which each in turn carry aMarshalInfo
describing the marshalling behaviors for the implementation. From the implementation classes, we could generate an additional set to represent eachMarshalAsAttribute
as it would be represented at runtime, and a collection (referencing that set) of eachMarshalParamsAs
collection. These can then be used by the interceptor to perform the necessary runtime checking to select the correct implementation class.Additional considerations
See RuntimeMarshalAsAttributeCollection from the
incremental-generator
branch. This was never represented in theinterceptors
branch because it was thought to be unnecessary due to the wayMethodReference
s were compared; #33 shows that this was misguided.