Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to customize default implementation of bonded<T> in C# #153

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
91 changes: 62 additions & 29 deletions cs/src/core/Clone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ static class Cache<SourceT>
}

/// <summary>
/// Create an instance of type T by deep cloning properties/fields of a source object of type SourceT.
/// Create an instance of type <typeparamref name="T"/> by deep cloning properties/fields of a source object of type <typeparamref name="SourceT"/>.
/// </summary>
/// <typeparam name="SourceT">type representing a source schema compatible with schema T</typeparam>
/// <typeparam name="SourceT">type representing a source schema compatible with schema <typeparamref name="T"/></typeparam>
/// <param name="source">source object to create a clone from</param>
/// <returns></returns>
public static T From<SourceT>(SourceT source)
Expand All @@ -31,72 +31,105 @@ public static T From<SourceT>(SourceT source)
}

/// <summary>
/// Utility for cloning objects of type SourceT.
/// Utility for cloning objects of type <typeparamref name="SourceT"/>.
/// </summary>
/// <typeparam name="SourceT">type representing a Bond schema</typeparam>
public class Cloner<SourceT>
{
readonly Func<object, object>[] clone;


/// <summary>
/// Create a cloner that makes clones of the same type <typeparamref name="SourceT"/> as source objects.
/// </summary>
public Cloner()
: this(typeof(SourceT))
{}

/// <summary>
/// Create a cloner that makes clones of the specified type.
/// </summary>
/// <param name="type">type of clone object, may be different than source object</param>
public Cloner(Type type)
: this(type, (IParser) null)
{}

/// <summary>
/// Create a cloner that makes clones of the specified type.
/// </summary>
/// <param name="type">type of clone object, may be different than source object</param>
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
public Cloner(Type type, IParser parser)
{
clone = Generate(type, new DeserializerTransform<object>(
(o, i) => clone[i](o)));
clone = Generate(type,
new DeserializerTransform<object>((o, i) => clone[i](o)),
parser);
}

/// <summary>
/// Create a cloner that uses specified factory and makes clones of the specified type.
/// Create a cloner that makes clones of the specified type.
/// </summary>
/// <param name="type">type of clone object, may be different than source object</param>
/// <param name="factory">factory implementing IFactory interface</param>
/// /// <param name="factory">factory implementing <see cref="IFactory"/> interface</param>
public Cloner(Type type, IFactory factory)
{
clone = Generate(type,
new DeserializerTransform<object>(
(o, i) => clone[i](o),
true,
(t1, t2) => factory.CreateObject(t1, t2),
(t1, t2, count) => factory.CreateContainer(t1, t2, count)));
}
: this(type, null, factory)
{}

/// <summary>
/// Create a cloner that uses specified factory and makes clones of the specified type.
/// </summary>
/// <param name="type">type of clone object, may be different than source object</param>
/// <param name="factory">factory delegate returning expressions to create objects</param>
public Cloner(Type type, Factory factory)
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
/// <param name="factory">factory implementing <see cref="IFactory"/> interface</param>
public Cloner(Type type, IParser parser, IFactory factory)
{
clone = Generate(type,
new DeserializerTransform<object>(
(o, i) => clone[i](o),
factory));
new DeserializerTransform<object>(
(o, i) => clone[i](o),
true,
(t1, t2) => factory.CreateObject(t1, t2),
(t1, t2, count) => factory.CreateContainer(t1, t2, count)),
parser);
}

/// <summary>
/// Create a cloner that makes clones of the same type SourceT as source objects.
/// Create a cloner that uses specified factory and makes clones of the specified type.
/// </summary>
public Cloner()
: this(typeof(SourceT))
/// <param name="type">type of clone object, may be different than source object</param>
/// <param name="factory">factory delegate returning expressions to create objects</param>
public Cloner(Type type, Factory factory)
: this(type, null, factory)
{}

/// <summary>
/// Clone the source object into an object of type T.
/// Create a cloner that uses specified factory and makes clones of the specified type.
/// </summary>
/// <param name="type">type of clone object, may be different than source object</param>
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
/// <param name="factory">factory delegate returning expressions to create objects</param>
public Cloner(Type type, IParser parser, Factory factory)
{
clone = Generate(type,
new DeserializerTransform<object>(
(o, i) => clone[i](o),
factory),
parser);
}

/// <summary>
/// Clone the source object into an object of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">type of result, must be the same as types specified during Cloner construction</typeparam>
/// <typeparam name="T">type of result, must be the same as types specified during <see cref="Cloner{SourceT}" /> construction</typeparam>
/// <param name="source">source object to be cloned</param>
/// <returns>clone of the source object projected on type T</returns>
/// <returns>clone of the source object projected on type <typeparamref name="T"/></returns>
public T Clone<T>(SourceT source)
{
return (T)clone[0](source);
}

static Func<object, object>[] Generate(Type type, DeserializerTransform<object> transform)
static Func<object, object>[] Generate(Type type, DeserializerTransform<object> transform, IParser parser)
{
var parser = new ObjectParser(typeof(SourceT));
parser = parser ?? new ObjectParser(typeof(SourceT));

return transform.Generate(parser, type).Select(lambda => lambda.Compile()).ToArray();
}
}
Expand Down
42 changes: 34 additions & 8 deletions cs/src/core/Deserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Bond
using Bond.IO;

/// <summary>
/// Deserialize objects of type T
/// Deserialize objects of type <typeparamref name="T"/>
/// </summary>
/// <typeparam name="T">Type representing a Bond schema</typeparam>
public static class Deserialize<T>
Expand All @@ -22,7 +22,7 @@ static class Cache<R>
}

/// <summary>
/// Deserialize an object of type T from a payload
/// Deserialize an object of type <typeparamref name="T"/> from a payload
/// </summary>
/// <typeparam name="R">Protocol reader</typeparam>
/// <param name="reader">Protocol reader representing payload</param>
Expand All @@ -34,7 +34,7 @@ public static T From<R>(R reader)
}

/// <summary>
/// Deserializer for a protocol reader R
/// Deserializer for a protocol reader <typeparamref name="R"/>
/// </summary>
/// <typeparam name="R">Protocol reader</typeparam>
public class Deserializer<R>
Expand Down Expand Up @@ -105,6 +105,18 @@ public Deserializer(Type type, IFactory factory, bool inlineNested)
: this(type, ParserFactory<R>.Create(type), factory, null, inlineNested)
{ }

/// <summary>
/// Create a deserializer instance for specified type, using a custom object factory
/// </summary>
/// <param name="type">Type representing a Bond schema</param>
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
/// <param name="factory">Factory providing expressions to create objects during deserialization</param>
/// <param name="inlineNested">Inline nested types if possible (optimizes for reduction of execution time
/// at the expense of initialization time and memory)</param>
public Deserializer(Type type, IParser parser, IFactory factory, bool inlineNested)
: this(type, parser, factory, null, inlineNested)
{ }

/// <summary>
/// Create a deserializer instance for specified type, using a custom object factory
/// </summary>
Expand All @@ -116,6 +128,18 @@ public Deserializer(Type type, Factory factory, bool inlineNested)
: this(type, ParserFactory<R>.Create(type), null, factory, inlineNested)
{ }

/// <summary>
/// Create a deserializer instance for specified type, using a custom object factory
/// </summary>
/// <param name="type">Type representing a Bond schema</param>
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
/// <param name="factory">Factory providing expressions to create objects during deserialization</param>
/// <param name="inlineNested">Inline nested types if possible (optimizes for reduction of execution time
/// at the expense of initialization time and memory)</param>
public Deserializer(Type type, IParser parser, Factory factory, bool inlineNested)
: this(type, parser, null, factory, inlineNested)
{ }

/// <summary>
/// Create a deserializer instance for specified type, using a custom object factory
/// </summary>
Expand Down Expand Up @@ -174,7 +198,7 @@ public Deserializer(Assembly precompiledAssembly, Type type)
}

/// <summary>
/// Deserialize an object of type T from a payload
/// Deserialize an object of type <typeparamref name="T"/> from a payload
/// </summary>
/// <typeparam name="T">Type representing a Bond schema</typeparam>
/// <param name="reader">Protocol reader representing the payload</param>
Expand Down Expand Up @@ -207,11 +231,13 @@ internal static string GetPrecompiledClassName(Type type, string suffix = null)
public static class Deserializer
{
/// <summary>
/// Deserialize an object from an IBonded&lt;T> instance using a specific deserializer
/// Deserialize an object from an <see cref="IBonded{T}"/> instance using a specific deserializer
/// </summary>
/// <param name="deserializer">Deserializer to be used to deserialize IBonded&lt;T> payload</param>
/// <param name="bonded">IBonded&lt;T> instance representing payload</param>
/// <remarks>Implemented as an extension method to avoid ICloneable&lt;R> constraint on Deserializer&lt;R></remarks>
/// <typeparam name="R">Protocol reader</typeparam>
/// <typeparam name="T">Type of source object in the bonded</typeparam>
/// <param name="deserializer">Deserializer to be used to deserialize <see cref="IBonded{T}"/> payload</param>
/// <param name="bonded"><see cref="IBonded{T}"/> instance representing payload</param>
/// <remarks>Implemented as an extension method to avoid <see cref="ICloneable{R}"/> constraint on <see cref="Deserializer{R}"/></remarks>
/// <returns>Deserialized object</returns>
public static T Deserialize<T, R>(this Deserializer<R> deserializer, IBonded<T> bonded)
where R : ICloneable<R>
Expand Down
37 changes: 26 additions & 11 deletions cs/src/core/Serializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ static class Cache<W, T>
}

/// <summary>
/// Serialize object of type T to protocol writer of type W
/// Serialize object of type <typeparamref name="T"/> to protocol writer of type <typeparamref name="W"/>
/// </summary>
/// <typeparam name="W">Protocol writer</typeparam>
/// <typeparam name="T">Type representing a Bond schema</typeparam>
Expand All @@ -31,31 +31,31 @@ public static void To<W, T>(W writer, T obj)
}

/// <summary>
/// Serialize IBonded&lt;T> to protocol writer of type W
/// Serialize <see cref="IBonded{T}" /> to protocol writer of type <typeparamref name="W"/>
/// </summary>
/// <typeparam name="W">Protocol writer</typeparam>
/// <typeparam name="T">Type representing a Bond schema</typeparam>
/// <param name="writer">Writer instance</param>
/// <param name="bonded">IBonded instance</param>
/// <param name="bonded"><see cref="IBonded"/> instance</param>
public static void To<W, T>(W writer, IBonded<T> bonded)
{
bonded.Serialize(writer);
}

/// <summary>
/// Serialize IBonded to protocol writer of type W
/// Serialize <see cref="IBonded"/> to protocol writer of type <typeparamref name="W"/>
/// </summary>
/// <typeparam name="W">Protocol writer</typeparam>
/// <param name="writer">Writer instance</param>
/// <param name="bonded">IBonded instance</param>
/// <param name="bonded"><see cref="IBonded"/> instance</param>
public static void To<W>(W writer, IBonded bonded)
{
bonded.Serialize(writer);
}
}

/// <summary>
/// Serializer for protocol writer W
/// Serializer for protocol writer <typeparamref name="W"/>
/// </summary>
/// <typeparam name="W">Protocol writer</typeparam>
public class Serializer<W>
Expand All @@ -66,29 +66,44 @@ public class Serializer<W>
/// Create a serializer for specified type
/// </summary>
/// <param name="type">Type representing a Bond schema</param>
public Serializer(Type type) : this(type, inlineNested: true) { }
public Serializer(Type type) : this(type, null, inlineNested: true) { }

/// <summary>
/// Create a serializer for specified type
/// </summary>
/// <param name="type">Type representing a Bond schema</param>
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
public Serializer(Type type, IParser parser) : this(type, parser, inlineNested: true) { }

/// <summary>
/// Create a serializer for specified type
/// </summary>
/// <param name="type">Type representing a Bond schema</param>
/// <param name="inlineNested">Indicates whether nested struct serialization code may be inlined</param>
public Serializer(Type type, bool inlineNested) : this(type, null, inlineNested) { }

/// <summary>
/// Create a serializer for specified type
/// </summary>
/// <param name="type">Type representing a Bond schema</param>
/// <param name="parser">Custom <see cref="IParser"/> instance</param>
/// <param name="inlineNested">Indicates whether nested struct serialization code may be inlined</param>
public Serializer(Type type, bool inlineNested)
public Serializer(Type type, IParser parser, bool inlineNested)
{
var parser = new ObjectParser(type);
parser = parser ?? new ObjectParser(type);
serialize = SerializerGeneratorFactory<object, W>.Create(
(o, w, i) => serialize[i](o, w), type, inlineNested)
.Generate(parser)
.Select(lambda => lambda.Compile()).ToArray();
}

/// <summary>
/// Serialize object using protocol writer of type W
/// Serialize object using protocol writer of type <typeparamref name="W"/>
/// </summary>
/// <param name="obj">Object to serialize</param>
/// <param name="writer">Writer instance</param>
/// <remarks>
/// The object must be of type used to create the Serializer, otherwise behavior is undefined
/// The object must be of type used to create the <see cref="Serializer{W}"/>, otherwise behavior is undefined
/// </remarks>
public void Serialize(object obj, W writer)
{
Expand Down
Loading