Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ internal abstract partial class MessageFormatterRpcMarshaledContextTracker
private static readonly ConcurrentDictionary<Type, (JsonRpcProxyOptions? ProxyOptions, JsonRpcTargetOptions TargetOptions, RpcMarshalableAttribute Attribute)> MarshaledTypes = new();
private static readonly JsonRpcTargetOptions RpcMarshalableInterfaceDefaultTargetOptions = new() { NotifyClientOfEvents = false, DisposeOnDisconnect = true };
private static readonly MethodInfo ReleaseMarshaledObjectMethodInfo = typeof(MessageFormatterRpcMarshaledContextTracker).GetMethod(nameof(ReleaseMarshaledObject), BindingFlags.NonPublic | BindingFlags.Instance)!;
private static readonly ConcurrentDictionary<Type, RpcMarshalableOptionalInterfaceAttribute[]> MarshalableOptionalInterfaces = new ConcurrentDictionary<Type, RpcMarshalableOptionalInterfaceAttribute[]>();
private static readonly ConcurrentDictionary<Type, RpcMarshalableOptionalInterfaceAttribute[]> MarshalableOptionalInterfaces = new();
private static readonly ConcurrentDictionary<Type, RpcMarshalableAttribute?> RpcMarshalableAttributeCache = new();

private readonly Dictionary<long, (RpcMarshaledContext Context, IDisposable Revert)> marshaledObjects = new Dictionary<long, (RpcMarshaledContext Context, IDisposable Revert)>();
private readonly JsonRpc jsonRpc;
Expand Down Expand Up @@ -103,12 +104,13 @@ internal static bool TryGetMarshalOptionsForType(
[NotNullWhen(true)] out JsonRpcTargetOptions? targetOptions,
[NotNullWhen(true)] out RpcMarshalableAttribute? rpcMarshalableAttribute)
{
if (TryGetMarshalOptionsForTypeHelper(typeShape.Type, defaultProxyOptions, out proxyOptions, out targetOptions, out rpcMarshalableAttribute))
bool? helperResult = TryGetMarshalOptionsForTypeHelper(typeShape.Type, defaultProxyOptions, out proxyOptions, out targetOptions, out rpcMarshalableAttribute);
if (helperResult is not null)
{
return true;
return helperResult.Value;
}

if (typeShape.Type.GetCustomAttribute<RpcMarshalableAttribute>() is RpcMarshalableAttribute marshalableAttribute)
if (TryGetRpcMarshalableAttribute(typeShape.Type, out RpcMarshalableAttribute? marshalableAttribute))
{
// Validation requires more trim annotations than our NativeAOT callers can provide.
// And besides, analyzers should have called out any issues at compile-time.
Expand All @@ -133,19 +135,23 @@ internal static bool TryGetMarshalOptionsForType(
[NotNullWhen(true)] out JsonRpcTargetOptions? targetOptions,
[NotNullWhen(true)] out RpcMarshalableAttribute? rpcMarshalableAttribute)
{
if (TryGetMarshalOptionsForTypeHelper(type, defaultProxyOptions, out proxyOptions, out targetOptions, out rpcMarshalableAttribute))
bool? helperResult = TryGetMarshalOptionsForTypeHelper(type, defaultProxyOptions, out proxyOptions, out targetOptions, out rpcMarshalableAttribute);
if (helperResult is not null)
{
// Because events are not checked by the Nerdbank.MessagePack formatter,
// Remove this check when issues related to https://github.com/eiriktsarpalis/PolyType/issues/226 are resolved in this file.
if (type.GetEvents().Length > 0)
if (helperResult is true)
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.MarshalableInterfaceHasEvents, type.FullName));
// Because events are not checked by the Nerdbank.MessagePack formatter,
// Remove this check when issues related to https://github.com/eiriktsarpalis/PolyType/issues/226 are resolved in this file.
if (type.GetEvents().Length > 0)
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.MarshalableInterfaceHasEvents, type.FullName));
}
}

return true;
return helperResult.Value;
}

if (type.GetCustomAttribute<RpcMarshalableAttribute>() is RpcMarshalableAttribute marshalableAttribute)
if (TryGetRpcMarshalableAttribute(type, out RpcMarshalableAttribute? marshalableAttribute))
{
// Validation requires more trim annotations than our NativeAOT callers can provide.
// And besides, analyzers should have called out any issues at compile-time.
Expand Down Expand Up @@ -195,7 +201,7 @@ internal static RpcMarshalableOptionalInterfaceAttribute[] GetMarshalableOptiona

foreach (RpcMarshalableOptionalInterfaceAttribute attribute in attributes)
{
if (attribute.OptionalInterface.GetCustomAttribute<RpcMarshalableAttribute>() is null)
if (!TryGetRpcMarshalableAttribute(attribute.OptionalInterface, out _))
{
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.RpcMarshalableOptionalInterfaceMustBeMarshalable, attribute.OptionalInterface.FullName));
}
Expand Down Expand Up @@ -423,7 +429,7 @@ internal MarshalToken GetToken(

protected abstract RpcTargetMetadata GetRpcTargetMetadata([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType);

private static bool TryGetMarshalOptionsForTypeHelper(
private static bool? TryGetMarshalOptionsForTypeHelper(
Type type,
JsonRpcProxyOptions defaultProxyOptions,
[NotNullWhen(true)] out JsonRpcProxyOptions? proxyOptions,
Expand All @@ -435,6 +441,7 @@ private static bool TryGetMarshalOptionsForTypeHelper(
rpcMarshalableAttribute = null;
if (type.IsInterface is false)
{
// Definitely not.
Comment thread
AArnott marked this conversation as resolved.
return false;
}

Expand All @@ -461,7 +468,8 @@ private static bool TryGetMarshalOptionsForTypeHelper(
}
}

return false;
// Unknown. Caller may want to do more work.
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] While more descriptive than the previous comment, this could be clearer. Consider: 'Return null to indicate the interface type requires further validation by the caller.'

Suggested change
// Unknown. Caller may want to do more work.
// Return null to indicate the interface type requires further validation by the caller.

Copilot uses AI. Check for mistakes.
return null;
}

/// <summary>
Expand Down Expand Up @@ -525,6 +533,12 @@ private static void ValidateMarshalableInterface(
}
}

private static bool TryGetRpcMarshalableAttribute(Type type, [NotNullWhen(true)] out RpcMarshalableAttribute? attribute)
{
attribute = RpcMarshalableAttributeCache.GetOrAdd(type, static type => type.GetCustomAttribute<RpcMarshalableAttribute>());
return attribute is not null;
}

/// <summary>
/// Releases memory associated with marshaled objects.
/// </summary>
Expand Down