Skip to content

Commit

Permalink
Support open generic metatypes
Browse files Browse the repository at this point in the history
  • Loading branch information
Turnerj committed Nov 4, 2021
1 parent c67c204 commit 11800ab
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 6 deletions.
48 changes: 48 additions & 0 deletions src/protobuf-net.Test/Meta/OpenGenericMetaType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using ProtoBuf.Meta;
using Xunit;

namespace ProtoBuf.Test.Meta
{
public class OpenGenericMetaTypeTests
{
public class OpenGenericTarget<T>
{
public T Value { get; set; }
}

[ProtoContract]
public class OpenGenericSurrogate<T>
{
[ProtoMember(1)]
public T Value { get; set; }


public static implicit operator OpenGenericTarget<T>(OpenGenericSurrogate<T> surrogate)
{
return surrogate == null ? null : new OpenGenericTarget<T>
{
Value = surrogate.Value
};
}

public static implicit operator OpenGenericSurrogate<T>(OpenGenericTarget<T> source)
{
return source == null ? null : new OpenGenericSurrogate<T>
{
Value = source.Value
};
}
}

[Fact]
public void OpenGenericMetaTypeSerialization()
{
RuntimeTypeModel.Default.Add(typeof(OpenGenericTarget<>)).SetSurrogate(typeof(OpenGenericSurrogate<>));

var instance = new OpenGenericTarget<string> { Value = "XYZ!" };
var clone = RuntimeTypeModel.Default.DeepClone(instance);

Assert.Equal(instance.Value, clone.Value);
}
}
}
8 changes: 8 additions & 0 deletions src/protobuf-net/Meta/MetaType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2482,5 +2482,13 @@ static string CommentSuffix(ProtoReservedAttribute reservation)
return " (" + comment.Trim() + ")";
}
}

internal MetaType GenerateGenericType(Type type)
{
var metaType = new MetaType(model, type, factory);
metaType.SetSurrogate(surrogateType.GetGenericTypeDefinition());
metaType._fields = _fields;
return metaType;
}
}
}
31 changes: 25 additions & 6 deletions src/protobuf-net/Meta/RuntimeTypeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -719,15 +719,34 @@ internal int FindOrAddAuto(Type type, bool demand, bool addWithContractOnly, boo
shouldAdd = addEvenIfAutoDisabled = true; // always add basic tuples, such as KeyValuePair
}

if (!shouldAdd || (
!type.IsEnum && addWithContractOnly && family == MetaType.AttributeFamily.None)
)
// for generic types, when no contract is set, see if a generic definition is registered and use that
if (type.IsGenericType && !type.IsGenericTypeDefinition && family == MetaType.AttributeFamily.None)
{
if (demand) ThrowUnexpectedType(type, this);
return key;
var genericTypeDefinition = type.GetGenericTypeDefinition();
key = types.IndexOf(MetaTypeFinder, genericTypeDefinition);
if (key >= 0)
{
var genericMetaType = (MetaType)types[key];
if (genericMetaType.Pending)
{
WaitOnLock();
}
metaType = genericMetaType.GenerateGenericType(type);
}
}

metaType = Create(type);
if (metaType is null)
{
if (!shouldAdd || (
!type.IsEnum && addWithContractOnly && family == MetaType.AttributeFamily.None)
)
{
if (demand) ThrowUnexpectedType(type, this);
return key;
}

metaType = Create(type);
}
}

metaType.Pending = true;
Expand Down

0 comments on commit 11800ab

Please sign in to comment.