mirror of
https://github.com/DeclanHoare/whoa.git
synced 2025-01-22 14:12:04 -05:00
you don't need OrderAttribute!
This commit is contained in:
parent
f2b90d32bb
commit
b77b3a1198
6 changed files with 407 additions and 204 deletions
70
README.md
70
README.md
|
@ -1,26 +1,72 @@
|
||||||
# Whoa
|
# Whoa
|
||||||
|
|
||||||
## About
|
## About
|
||||||
Whoa is a serialisation library for C#. Its output is ultra small and
|
Whoa is a serialisation library for .NET. Its output is ultra small and
|
||||||
you can add members to your type and still be able to deserialise old
|
you can add members to your type and still be able to deserialise old
|
||||||
versions. Since it stores the bare minimum of type data, it is a bit
|
versions. Since it stores the bare minimum of type data, it is a bit
|
||||||
more finicky than other serialisation solutions like BinaryFormatter,
|
more finicky than other serialisation solutions like BinaryFormatter,
|
||||||
but produces much smaller output.
|
but produces much smaller output.
|
||||||
|
|
||||||
|
The format may change in non-backwards-compatible ways sometimes as new
|
||||||
|
features are added. To make sure your data can be deserialised, use the
|
||||||
|
same version of Whoa for serialisation and deserialisation. That said,
|
||||||
|
whenever feasible, backwards compatibility will be preserved, and
|
||||||
|
eventually the format will be finalised.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
For Whoa to produce meaningful output, your type will need to have a
|
Whoa is static and stateless. To serialise an object:
|
||||||
public constructor with no arguments, and every field or property that
|
|
||||||
you would like to save needs to be public (properties must have a public
|
|
||||||
getter AND a public setter) and have a Whoa.OrderAttribute. Also, if you
|
|
||||||
want to preserve backwards compatibility, don't rearrange or remove
|
|
||||||
any of the members with OrderAttributes. You can, however, add new ones
|
|
||||||
to the end of your class without issue.
|
|
||||||
|
|
||||||
To serialise an object:
|
`Whoa.Whoa.SerialiseObject(outstream, object[, options]);`
|
||||||
`Whoa.Whoa.SerialiseObject(outstream, obj);`
|
|
||||||
|
|
||||||
To deserialise an object:
|
... and to deserialise it:
|
||||||
`Whoa.Whoa.DeserialiseObject<T>(instream);`
|
|
||||||
|
|
||||||
|
`Whoa.Whoa.DeserialiseObject<type>(instream[, options]);`
|
||||||
|
|
||||||
|
There are also reflection-friendly interfaces to these functions:
|
||||||
|
|
||||||
|
`Whoa.Whoa.SerialiseObject(type, outstream, object[, options]);`
|
||||||
|
|
||||||
|
`Whoa.Whoa.DeserialiseObject(type, instream[, options]);`
|
||||||
|
|
||||||
|
If you'd like to take control of the serialisation of a particular
|
||||||
|
class, you should define a derivative of ISpecialSerialiser, instantiate
|
||||||
|
it, and pass it to Whoa with:
|
||||||
|
|
||||||
|
`Whoa.Whoa.RegisterSpecialSerialiser(instance);`
|
||||||
|
|
||||||
|
ISpecialSerialiser is a generic interface. Your derivative should fill
|
||||||
|
in the type argument with the type you want to handle. Whoa contains
|
||||||
|
inbuilt special serialisers for:
|
||||||
|
|
||||||
|
* System.Guid
|
||||||
|
* System.BigInteger
|
||||||
|
* System.String
|
||||||
|
* System.DateTime
|
||||||
|
* System.Drawing.Color
|
||||||
|
* System.Drawing.Font
|
||||||
|
* System.Drawing.Image
|
||||||
|
* System.IO.Stream
|
||||||
|
|
||||||
|
It will also handle arrays, Lists, and Dictionaries of types it knows
|
||||||
|
automatically, and numeric types and enums are passed to BinaryWriter.
|
||||||
|
|
||||||
|
By default, Whoa requires the use of an OrderAttribute on each member
|
||||||
|
of your class that you would like serialised, and it will only touch
|
||||||
|
public members. It is also perfectly happy to serialise classes that do
|
||||||
|
not have a SerializableAttribute. These characteristics can be changed
|
||||||
|
by passing flags from the SerialisationOptions enum.
|
||||||
|
Of particular note is the NonSerialized mode. This will remove the
|
||||||
|
requirement for Order attributes and instead (de)serialise the members
|
||||||
|
in the order they are received from GetMembers(). The .NET documentation
|
||||||
|
states that this order is arbitrary, but on both Microsoft's framework
|
||||||
|
and Mono, it seems to always match declaration order, so it's not
|
||||||
|
currently a practical issue. In this mode, you can exclude members from
|
||||||
|
serialisation by giving them a NonSerializedAttribute.
|
||||||
|
Also, remember that the options will need to be the same on
|
||||||
|
serialisation and deserialisation.
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
* Reference semantics
|
||||||
|
* Remembering derived type information
|
||||||
|
|
|
@ -19,6 +19,7 @@ using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Drawing;
|
||||||
using Whoa;
|
using Whoa;
|
||||||
|
|
||||||
namespace Whoa.Tests
|
namespace Whoa.Tests
|
||||||
|
@ -42,87 +43,95 @@ namespace Whoa.Tests
|
||||||
|
|
||||||
private class Record
|
private class Record
|
||||||
{
|
{
|
||||||
[Order]
|
|
||||||
public string title;
|
public string title;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public string artist;
|
public string artist;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public int rpm;
|
|
||||||
|
|
||||||
[Order]
|
public int rpm { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public double price;
|
public double price;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool inLibrary;
|
public bool inLibrary;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool otherBool;
|
public bool otherBool;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public List<string> songs;
|
public List<string> songs;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public Guid guidForSomeReason;
|
public Guid guidForSomeReason;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public List<bool> moreBools;
|
public List<bool> moreBools;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public string awards;
|
public string awards;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public int? profits;
|
public int? profits;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public int? losses;
|
public int? losses;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public List<int> somethingElse;
|
public List<int> somethingElse;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public Dictionary<string, string> staff;
|
public Dictionary<string, string> staff;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public Dictionary<string, string> plausibleSampleData;
|
public Dictionary<string, string> plausibleSampleData;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public List<bool> notActuallyMoreBools;
|
public List<bool> notActuallyMoreBools;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool boolThree;
|
public bool boolThree;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool boolFour;
|
public bool boolFour;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool boolFive;
|
public bool boolFive;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool boolSix;
|
public bool boolSix;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool boolSeven;
|
public bool boolSeven;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public bool boolEight;
|
public bool boolEight;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public BigInteger reallyReallyReallyReallyReallyReallyBigNumber;
|
public BigInteger reallyReallyReallyReallyReallyReallyBigNumber;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public DateTime releaseDate;
|
public DateTime releaseDate;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public RecordType kind;
|
public RecordType kind;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public Details details;
|
public Details details;
|
||||||
|
|
||||||
[Order]
|
|
||||||
public string[] thisIsAnArrayNotAList;
|
public string[] thisIsAnArrayNotAList;
|
||||||
|
|
||||||
|
public Image img;
|
||||||
|
|
||||||
|
public Color colour;
|
||||||
|
|
||||||
|
public Font font;
|
||||||
|
|
||||||
|
public Stream data;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
string ret = $@"{title}
|
string ret = $@"{title}
|
||||||
|
@ -150,6 +159,8 @@ Released: {releaseDate}
|
||||||
ret += $"{pair.Key} - {pair.Value}" + Environment.NewLine;
|
ret += $"{pair.Key} - {pair.Value}" + Environment.NewLine;
|
||||||
ret += "Null dictionaries work: " + (plausibleSampleData == null ? "Yes" : "No") + Environment.NewLine;
|
ret += "Null dictionaries work: " + (plausibleSampleData == null ? "Yes" : "No") + Environment.NewLine;
|
||||||
ret += "Null bool lists work: " + (notActuallyMoreBools == null ? "Yes" : "No") + Environment.NewLine;
|
ret += "Null bool lists work: " + (notActuallyMoreBools == null ? "Yes" : "No") + Environment.NewLine;
|
||||||
|
byte[] buf = new byte[data.Length];
|
||||||
|
data.Read(buf, 0, buf.Length);
|
||||||
ret += $@"boolThree = {boolThree}
|
ret += $@"boolThree = {boolThree}
|
||||||
boolFour = {boolFour}
|
boolFour = {boolFour}
|
||||||
boolFive = {boolFive}
|
boolFive = {boolFive}
|
||||||
|
@ -162,13 +173,17 @@ Is catchy: {details.HasFlag(Details.Catchy)}.
|
||||||
Is popular: {details.HasFlag(Details.Popular)}.
|
Is popular: {details.HasFlag(Details.Popular)}.
|
||||||
Is terrible: {details.HasFlag(Details.Terrible)}.
|
Is terrible: {details.HasFlag(Details.Terrible)}.
|
||||||
The second entry of an array that isn't a list is: {thisIsAnArrayNotAList[1]}
|
The second entry of an array that isn't a list is: {thisIsAnArrayNotAList[1]}
|
||||||
|
{img.Width}
|
||||||
|
{colour.R} {colour.G} {colour.B} {colour.A}
|
||||||
|
{font}
|
||||||
|
{System.Text.Encoding.UTF8.GetString(buf)}
|
||||||
";
|
";
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
using (var str = new MemoryStream())
|
using (var str = args.Length > 0 ? (File.Open(args[0], FileMode.Create) as Stream) : (new MemoryStream() as Stream))
|
||||||
{
|
{
|
||||||
var rec = new Record()
|
var rec = new Record()
|
||||||
{
|
{
|
||||||
|
@ -216,18 +231,16 @@ The second entry of an array that isn't a list is: {thisIsAnArrayNotAList[1]}
|
||||||
"The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this.",
|
"The freedom to study how the program works, and change it so it does your computing as you wish (freedom 1). Access to the source code is a precondition for this.",
|
||||||
"The freedom to redistribute copies so you can help your neighbor (freedom 2).",
|
"The freedom to redistribute copies so you can help your neighbor (freedom 2).",
|
||||||
"The freedom to distribute copies of your modified versions to others (freedom 3). By doing this you can give the whole community a chance to benefit from your changes. Access to the source code is a precondition for this."
|
"The freedom to distribute copies of your modified versions to others (freedom 3). By doing this you can give the whole community a chance to benefit from your changes. Access to the source code is a precondition for this."
|
||||||
}
|
},
|
||||||
|
img = new Bitmap(800, 600),
|
||||||
|
colour = Color.FromArgb(255, 127, 0),
|
||||||
|
font = new Font("Times New Roman", 12),
|
||||||
|
data = new MemoryStream(System.Text.Encoding.UTF8.GetBytes("what's up, gamers?"))
|
||||||
};
|
};
|
||||||
string expected = rec.ToString();
|
string expected = rec.ToString();
|
||||||
Whoa.SerialiseObject(str, rec);
|
Whoa.SerialiseObject(str, rec, SerialisationOptions.NonSerialized);
|
||||||
if (args.Length > 0) // Save output for debugging.
|
|
||||||
{
|
|
||||||
str.Position = 0;
|
|
||||||
using (var fobj = File.OpenWrite(args[0]))
|
|
||||||
str.CopyTo(fobj);
|
|
||||||
}
|
|
||||||
str.Position = 0;
|
str.Position = 0;
|
||||||
var res = Whoa.DeserialiseObject<Record>(str);
|
var res = Whoa.DeserialiseObject<Record>(str, SerialisationOptions.NonSerialized);
|
||||||
string actual = res.ToString();
|
string actual = res.ToString();
|
||||||
Console.Write("Test ");
|
Console.Write("Test ");
|
||||||
if (expected == actual)
|
if (expected == actual)
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Numerics" />
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.4.0.0")]
|
[assembly: AssemblyVersion("1.5.0.0")]
|
||||||
[assembly: AssemblyFileVersion("1.4.0.0")]
|
[assembly: AssemblyFileVersion("1.5.0.0")]
|
||||||
|
|
444
Whoa/Whoa.cs
444
Whoa/Whoa.cs
|
@ -24,114 +24,243 @@ using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
namespace Whoa
|
namespace Whoa
|
||||||
{
|
{
|
||||||
public static class Whoa
|
public static class Whoa
|
||||||
{
|
{
|
||||||
private class SpecialSerialiserAttribute: Attribute
|
private enum SpecialSizes
|
||||||
{
|
{
|
||||||
public Type t { get; private set; }
|
Null = -1,
|
||||||
public SpecialSerialiserAttribute(Type in_t)
|
ReferenceEqual = -2 // not used yet...
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<Type, dynamic> SpecialSerialisers = new Dictionary<Type, dynamic>();
|
||||||
|
|
||||||
|
static Whoa()
|
||||||
|
{
|
||||||
|
foreach (Type t in typeof(Whoa).GetNestedTypes(BindingFlags.NonPublic))
|
||||||
{
|
{
|
||||||
t = in_t;
|
if (t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ISpecialSerialiser<>)))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SpecialDeserialiserAttribute: Attribute
|
|
||||||
{
|
|
||||||
public Type t { get; private set; }
|
|
||||||
public SpecialDeserialiserAttribute(Type in_t)
|
|
||||||
{
|
|
||||||
t = in_t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SpecialSerialiser(typeof(Guid))]
|
|
||||||
private static void SerialiseGuid(Stream fobj, dynamic obj)
|
|
||||||
{
|
|
||||||
fobj.Write(obj.ToByteArray(), 0, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
[SpecialDeserialiser(typeof(Guid))]
|
|
||||||
private static object DeserialiseGuid(Stream fobj)
|
|
||||||
{
|
|
||||||
var guid = new byte[16];
|
|
||||||
fobj.Read(guid, 0, 16);
|
|
||||||
return new Guid(guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
[SpecialSerialiser(typeof(BigInteger))]
|
|
||||||
private static void SerialiseBigInt(Stream fobj, dynamic obj)
|
|
||||||
{
|
|
||||||
SerialiseObject(fobj, new List<byte>(obj.ToByteArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[SpecialDeserialiser(typeof(BigInteger))]
|
|
||||||
private static object DeserialiseBigInt(Stream fobj)
|
|
||||||
{
|
|
||||||
return new BigInteger((DeserialiseObject(typeof(List<byte>), fobj) as List<byte>).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
[SpecialSerialiser(typeof(string))]
|
|
||||||
private static void SerialiseString(Stream fobj, dynamic obj)
|
|
||||||
{
|
|
||||||
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
|
||||||
{
|
|
||||||
byte[] bytes = null;
|
|
||||||
int len;
|
|
||||||
if (obj == null)
|
|
||||||
len = -1;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
bytes = Encoding.UTF8.GetBytes(obj);
|
RegisterSpecialSerialiser((dynamic)Activator.CreateInstance(t));
|
||||||
len = bytes.Length;
|
|
||||||
}
|
|
||||||
typeof(BinaryWriter).GetMethod("Write7BitEncodedInt", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(write, new object[] { len });
|
|
||||||
if (bytes != null)
|
|
||||||
fobj.Write(bytes, 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SpecialDeserialiser(typeof(string))]
|
|
||||||
private static object DeserialiseString(Stream fobj)
|
|
||||||
{
|
|
||||||
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
|
||||||
{
|
|
||||||
int len = (int)typeof(BinaryReader).GetMethod("Read7BitEncodedInt", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(read, new object[] { });
|
|
||||||
if (len < 0)
|
|
||||||
return null;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var bytes = new byte[len];
|
|
||||||
fobj.Read(bytes, 0, len);
|
|
||||||
return Encoding.UTF8.GetString(bytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[SpecialSerialiser(typeof(DateTime))]
|
public static void RegisterSpecialSerialiser<T>(ISpecialSerialiser<T> serialiser)
|
||||||
private static void SerialiseDateTime(Stream fobj, dynamic obj)
|
|
||||||
{
|
{
|
||||||
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
SpecialSerialisers.Add(typeof(T), serialiser);
|
||||||
write.Write(obj.ToBinary());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SpecialDeserialiser(typeof(DateTime))]
|
private class GuidSerialiser: ISpecialSerialiser<Guid>
|
||||||
private static object DeserialiseDateTime(Stream fobj)
|
|
||||||
{
|
{
|
||||||
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
public void SerialiseObject(Stream fobj, Guid obj)
|
||||||
return DateTime.FromBinary(read.ReadInt64());
|
{
|
||||||
|
fobj.Write(obj.ToByteArray(), 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
var guid = new byte[16];
|
||||||
|
fobj.Read(guid, 0, 16);
|
||||||
|
return new Guid(guid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IOrderedEnumerable<MemberInfo> Members(Type t)
|
private class BigIntegerSerialiser: ISpecialSerialiser<BigInteger>
|
||||||
{
|
{
|
||||||
return t.GetProperties().Select(m => m as MemberInfo).Concat(t.GetFields().Select(m => m as MemberInfo)).Where(m => (m.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute) != null).OrderBy(m => (m.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute).Order);
|
public void SerialiseObject(Stream fobj, BigInteger obj)
|
||||||
|
{
|
||||||
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
|
{
|
||||||
|
byte[] bytes = obj.ToByteArray();
|
||||||
|
write.Write(bytes.Length);
|
||||||
|
write.Write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
|
return new BigInteger(read.ReadBytes(read.ReadInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StringSerialiser: ISpecialSerialiser<string>
|
||||||
|
{
|
||||||
|
private class FriendlyBinaryWriter: BinaryWriter
|
||||||
|
{
|
||||||
|
public FriendlyBinaryWriter(Stream fobj) : base(fobj, Encoding.UTF8, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public void Write7BitEncodedIntPublic(int value)
|
||||||
|
{
|
||||||
|
Write7BitEncodedInt(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FriendlyBinaryReader: BinaryReader
|
||||||
|
{
|
||||||
|
public FriendlyBinaryReader(Stream fobj) : base(fobj, Encoding.UTF8, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public int Read7BitEncodedIntPublic()
|
||||||
|
{
|
||||||
|
return Read7BitEncodedInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void SerialiseObject(Stream fobj, string obj)
|
||||||
|
{
|
||||||
|
using (var write = new FriendlyBinaryWriter(fobj))
|
||||||
|
{
|
||||||
|
byte[] bytes = null;
|
||||||
|
int len;
|
||||||
|
if (obj == null)
|
||||||
|
len = (int)SpecialSizes.Null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes = Encoding.UTF8.GetBytes(obj);
|
||||||
|
len = bytes.Length;
|
||||||
|
}
|
||||||
|
write.Write7BitEncodedIntPublic(len);
|
||||||
|
if (bytes != null)
|
||||||
|
write.Write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
using (var read = new FriendlyBinaryReader(fobj))
|
||||||
|
{
|
||||||
|
int len = read.Read7BitEncodedIntPublic();
|
||||||
|
if (len == (int)SpecialSizes.Null)
|
||||||
|
return null;
|
||||||
|
return Encoding.UTF8.GetString(read.ReadBytes(len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DateTimeSerialiser: ISpecialSerialiser<DateTime>
|
||||||
|
{
|
||||||
|
public void SerialiseObject(Stream fobj, DateTime obj)
|
||||||
|
{
|
||||||
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
|
write.Write(obj.ToBinary());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
|
return DateTime.FromBinary(read.ReadInt64());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ColorSerialiser: ISpecialSerialiser<Color>
|
||||||
|
{
|
||||||
|
public void SerialiseObject(Stream fobj, Color obj)
|
||||||
|
{
|
||||||
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
|
write.Write(obj.ToArgb());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
|
return Color.FromArgb(read.ReadInt32());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FontSerialiser: ISpecialSerialiser<Font>
|
||||||
|
{
|
||||||
|
public void SerialiseObject(Stream fobj, Font obj)
|
||||||
|
{
|
||||||
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
|
{
|
||||||
|
write.Write(obj.FontFamily.Name);
|
||||||
|
write.Write(obj.Size);
|
||||||
|
write.Write((int)obj.Style);
|
||||||
|
write.Write((int)obj.Unit);
|
||||||
|
write.Write(obj.GdiCharSet);
|
||||||
|
write.Write(obj.GdiVerticalFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
|
return new Font(read.ReadString(), read.ReadSingle(), (FontStyle)read.ReadInt32(), (GraphicsUnit)read.ReadInt32(), read.ReadByte(), read.ReadBoolean());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ImageSerialiser: ISpecialSerialiser<Image>
|
||||||
|
{
|
||||||
|
public void SerialiseObject(Stream fobj, Image obj)
|
||||||
|
{
|
||||||
|
// Images can be saved to Streams but the image data will
|
||||||
|
// be "invalid" if the Stream it is written to starts at a
|
||||||
|
// non-zero position, so we need to buffer.
|
||||||
|
using (var mstr = new MemoryStream())
|
||||||
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
|
{
|
||||||
|
obj.Save(mstr, ImageFormat.Png);
|
||||||
|
mstr.Position = 0;
|
||||||
|
write.Write((int)mstr.Length);
|
||||||
|
mstr.CopyTo(fobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Image DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
// Images can be loaded from Streams but they must remain
|
||||||
|
// open for the lifetime of the Image, so, to avoid needing
|
||||||
|
// a handle on the file being loaded from, we buffer on read
|
||||||
|
// too.
|
||||||
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
|
return Image.FromStream(new MemoryStream(read.ReadBytes(read.ReadInt32())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StreamSerialiser: ISpecialSerialiser<Stream>
|
||||||
|
{
|
||||||
|
public void SerialiseObject(Stream fobj, Stream obj)
|
||||||
|
{
|
||||||
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
|
{
|
||||||
|
obj.Position = 0;
|
||||||
|
write.Write((int)obj.Length);
|
||||||
|
obj.CopyTo(fobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream DeserialiseObject(Stream fobj)
|
||||||
|
{
|
||||||
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
|
return new MemoryStream(read.ReadBytes(read.ReadInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IOrderedEnumerable<MemberInfo> Members(Type t, SerialisationOptions options)
|
||||||
|
{
|
||||||
|
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;
|
||||||
|
if (options.HasFlag(SerialisationOptions.NonPublic))
|
||||||
|
flags |= BindingFlags.NonPublic;
|
||||||
|
if (options.HasFlag(SerialisationOptions.FlattenHierarchy))
|
||||||
|
flags |= BindingFlags.FlattenHierarchy;
|
||||||
|
var all = t.GetMembers(flags).Where(m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property);
|
||||||
|
int i = 0;
|
||||||
|
if (options.HasFlag(SerialisationOptions.NonSerialized))
|
||||||
|
return all.Where(m => (m.GetCustomAttributes(typeof(NonSerializedAttribute), false).SingleOrDefault() == null)).OrderBy(m => i++);
|
||||||
|
else
|
||||||
|
return all.Where(m => (m.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() != null)).OrderBy(m => (m.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute).Order);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<bool> ReadBitfield(Stream fobj, int count)
|
private static List<bool> ReadBitfield(Stream fobj, int count)
|
||||||
{
|
{
|
||||||
if (count < 0)
|
if (count == (int)SpecialSizes.Null)
|
||||||
return null;
|
return null;
|
||||||
sbyte bit = 7;
|
sbyte bit = 7;
|
||||||
int cur = 0;
|
int cur = 0;
|
||||||
|
@ -173,32 +302,39 @@ namespace Whoa
|
||||||
fobj.Write(bitfields, 0, bitfields.Length);
|
fobj.Write(bitfields, 0, bitfields.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T DeserialiseObject<T>(Stream fobj)
|
public static T DeserialiseObject<T>(Stream fobj, SerialisationOptions options = SerialisationOptions.None)
|
||||||
{
|
{
|
||||||
return (T)DeserialiseObject(typeof(T), fobj);
|
return (T)DeserialiseObject(typeof(T), fobj, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object DeserialiseObjectWorker(Type t, Stream fobj)
|
private static object DeserialiseObjectWorker(Type t, Stream fobj, SerialisationOptions options)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine("Deserialising object of type: " + t.ToString());
|
Console.WriteLine("Deserialising object of type: " + t.ToString());
|
||||||
#endif
|
#endif
|
||||||
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||||
{
|
{
|
||||||
|
// Look for a special serialiser for this type.
|
||||||
|
dynamic special = null;
|
||||||
|
if (SpecialSerialisers.TryGetValue(t, out special))
|
||||||
|
{
|
||||||
|
return special.DeserialiseObject(fobj);
|
||||||
|
}
|
||||||
|
|
||||||
if (t.IsEnum)
|
if (t.IsEnum)
|
||||||
{
|
{
|
||||||
return Enum.ToObject(t, DeserialiseObjectWorker(Enum.GetUnderlyingType(t), fobj));
|
return Enum.ToObject(t, DeserialiseObjectWorker(Enum.GetUnderlyingType(t), fobj, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.IsArray)
|
if (t.IsArray)
|
||||||
{
|
{
|
||||||
int numelems = read.ReadInt32();
|
int numelems = read.ReadInt32();
|
||||||
if (numelems < 0)
|
if (numelems == (int)SpecialSizes.Null)
|
||||||
return null;
|
return null;
|
||||||
dynamic reta = Activator.CreateInstance(t, new object[] { numelems });
|
dynamic reta = Activator.CreateInstance(t, new object[] { numelems });
|
||||||
Type elemtype = t.GetElementType();
|
Type elemtype = t.GetElementType();
|
||||||
for (int i = 0; i < numelems; i++)
|
for (int i = 0; i < numelems; i++)
|
||||||
reta[i] = (dynamic)DeserialiseObjectWorker(elemtype, fobj);
|
reta[i] = (dynamic)DeserialiseObjectWorker(elemtype, fobj, options);
|
||||||
return reta;
|
return reta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,61 +345,49 @@ namespace Whoa
|
||||||
if (gent == typeof(Nullable<>))
|
if (gent == typeof(Nullable<>))
|
||||||
{
|
{
|
||||||
bool extant = read.ReadBoolean();
|
bool extant = read.ReadBoolean();
|
||||||
return extant ? DeserialiseObjectWorker(t.GetGenericArguments()[0], fobj) : null;
|
return extant ? DeserialiseObjectWorker(t.GetGenericArguments()[0], fobj, options) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gent == typeof(List<>))
|
if (gent == typeof(List<>))
|
||||||
{
|
{
|
||||||
int numelems = read.ReadInt32();
|
int numelems = read.ReadInt32();
|
||||||
if (numelems < 0)
|
if (numelems == (int)SpecialSizes.Null)
|
||||||
return null;
|
return null;
|
||||||
dynamic retl = Activator.CreateInstance(t, new object[] { numelems });
|
dynamic retl = Activator.CreateInstance(t, new object[] { numelems });
|
||||||
Type elemtype = t.GetGenericArguments()[0];
|
Type elemtype = t.GetGenericArguments()[0];
|
||||||
for (int i = 0; i < numelems; i++)
|
for (int i = 0; i < numelems; i++)
|
||||||
retl.Add((dynamic)DeserialiseObjectWorker(elemtype, fobj));
|
retl.Add((dynamic)DeserialiseObjectWorker(elemtype, fobj, options));
|
||||||
return retl;
|
return retl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gent == typeof(Dictionary<,>))
|
if (gent == typeof(Dictionary<,>))
|
||||||
{
|
{
|
||||||
int numpairs = read.ReadInt32();
|
int numpairs = read.ReadInt32();
|
||||||
if (numpairs < 0)
|
if (numpairs == (int)SpecialSizes.Null)
|
||||||
return null;
|
return null;
|
||||||
dynamic retd = Activator.CreateInstance(t, new object[] { numpairs });
|
dynamic retd = Activator.CreateInstance(t, new object[] { numpairs });
|
||||||
Type[] arguments = t.GetGenericArguments();
|
Type[] arguments = t.GetGenericArguments();
|
||||||
for (int i = 0; i < numpairs; i++)
|
for (int i = 0; i < numpairs; i++)
|
||||||
{
|
{
|
||||||
dynamic key = DeserialiseObjectWorker(arguments[0], fobj);
|
dynamic key = DeserialiseObjectWorker(arguments[0], fobj, options);
|
||||||
dynamic val = DeserialiseObjectWorker(arguments[1], fobj);
|
dynamic val = DeserialiseObjectWorker(arguments[1], fobj, options);
|
||||||
retd.Add(key, val);
|
retd.Add(key, val);
|
||||||
}
|
}
|
||||||
return retd;
|
return retd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A little self reflection.
|
|
||||||
var specialmethod = typeof(Whoa).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).FirstOrDefault(m =>
|
|
||||||
{
|
|
||||||
var attr = m.GetCustomAttributes(typeof(SpecialDeserialiserAttribute), false).SingleOrDefault() as SpecialDeserialiserAttribute;
|
|
||||||
if (attr == null)
|
|
||||||
return false;
|
|
||||||
return attr.t == t;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (specialmethod != null)
|
|
||||||
return specialmethod.Invoke(null, new object[] { fobj });
|
|
||||||
|
|
||||||
var readermethod = typeof(BinaryReader).GetMethods().FirstOrDefault(m => m.Name.Length > 4 && m.Name.StartsWith("Read") && m.ReturnType == t);
|
var readermethod = typeof(BinaryReader).GetMethods().FirstOrDefault(m => m.Name.Length > 4 && m.Name.StartsWith("Read") && m.ReturnType == t);
|
||||||
if (readermethod != null)
|
if (readermethod != null)
|
||||||
return readermethod.Invoke(read, new object[] { });
|
return readermethod.Invoke(read, new object[] { });
|
||||||
|
|
||||||
int nummembers = read.ReadInt32();
|
int nummembers = read.ReadInt32();
|
||||||
if (nummembers < 0)
|
if (nummembers == (int)SpecialSizes.Null)
|
||||||
return null;
|
return null;
|
||||||
object ret = t.GetConstructor(Type.EmptyTypes).Invoke(new object[] { });
|
object ret = t.GetConstructor(Type.EmptyTypes).Invoke(new object[] { });
|
||||||
var bools = new List<dynamic>();
|
var bools = new List<dynamic>();
|
||||||
|
|
||||||
foreach (dynamic member in Members(t).Take(nummembers))
|
foreach (dynamic member in Members(t, options).Take(nummembers))
|
||||||
{
|
{
|
||||||
Type memt;
|
Type memt;
|
||||||
if (member.MemberType == MemberTypes.Field)
|
if (member.MemberType == MemberTypes.Field)
|
||||||
|
@ -278,7 +402,7 @@ namespace Whoa
|
||||||
else if (memt == typeof(bool[]))
|
else if (memt == typeof(bool[]))
|
||||||
member.SetValue(ret, ReadBitfield(fobj, read.ReadInt32()).ToArray());
|
member.SetValue(ret, ReadBitfield(fobj, read.ReadInt32()).ToArray());
|
||||||
else
|
else
|
||||||
member.SetValue(ret, DeserialiseObjectWorker(memt, fobj));
|
member.SetValue(ret, DeserialiseObjectWorker(memt, fobj, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bools.Count > 0)
|
if (bools.Count > 0)
|
||||||
|
@ -291,22 +415,32 @@ namespace Whoa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SerialiseObject(Stream fobj, dynamic obj)
|
public static void SerialiseObject<T>(Stream fobj, T obj, SerialisationOptions options = SerialisationOptions.None)
|
||||||
{
|
{
|
||||||
SerialiseObject(fobj, obj, obj.GetType());
|
Type t = typeof(T);
|
||||||
|
if ((t == typeof(object)) && obj != null)
|
||||||
|
t = obj.GetType();
|
||||||
|
SerialiseObject(t, fobj, obj, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SerialiseObjectWorker(Stream fobj, dynamic obj, Type t)
|
private static void SerialiseObjectWorker(Stream fobj, dynamic obj, Type t, SerialisationOptions options)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Console.WriteLine("Serialising object of type: " + t.ToString());
|
Console.WriteLine("Serialising object of type: " + t.ToString());
|
||||||
#endif
|
#endif
|
||||||
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||||
{
|
{
|
||||||
|
// Look for a special serialiser for this type.
|
||||||
|
dynamic special = null;
|
||||||
|
if (SpecialSerialisers.TryGetValue(t, out special))
|
||||||
|
{
|
||||||
|
special.SerialiseObject(fobj, obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (t.IsEnum)
|
if (t.IsEnum)
|
||||||
{
|
{
|
||||||
Type realt = Enum.GetUnderlyingType(t);
|
Type realt = Enum.GetUnderlyingType(t);
|
||||||
SerialiseObjectWorker(fobj, Convert.ChangeType(obj, realt), realt);
|
SerialiseObjectWorker(fobj, Convert.ChangeType(obj, realt), realt, options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,12 +448,12 @@ namespace Whoa
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
{
|
{
|
||||||
write.Write(-1);
|
write.Write((int)SpecialSizes.Null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
write.Write(obj.Length);
|
write.Write(obj.Length);
|
||||||
foreach (dynamic item in obj)
|
foreach (dynamic item in obj)
|
||||||
SerialiseObjectWorker(fobj, item, item.GetType());
|
SerialiseObjectWorker(fobj, item, item.GetType(), options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +466,7 @@ namespace Whoa
|
||||||
bool extant = obj != null;
|
bool extant = obj != null;
|
||||||
write.Write(extant);
|
write.Write(extant);
|
||||||
if (extant)
|
if (extant)
|
||||||
SerialiseObjectWorker(fobj, obj, t.GetGenericArguments()[0]);
|
SerialiseObjectWorker(fobj, obj, t.GetGenericArguments()[0], options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,12 +474,12 @@ namespace Whoa
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
{
|
{
|
||||||
write.Write(-1);
|
write.Write((int)SpecialSizes.Null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
write.Write(obj.Count);
|
write.Write(obj.Count);
|
||||||
foreach (dynamic item in obj)
|
foreach (dynamic item in obj)
|
||||||
SerialiseObjectWorker(fobj, item, item.GetType());
|
SerialiseObjectWorker(fobj, item, item.GetType(), options);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,36 +487,22 @@ namespace Whoa
|
||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
{
|
{
|
||||||
write.Write(-1);
|
write.Write((int)SpecialSizes.Null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
write.Write(obj.Count);
|
write.Write(obj.Count);
|
||||||
foreach (dynamic pair in obj)
|
foreach (dynamic pair in obj)
|
||||||
{
|
{
|
||||||
SerialiseObjectWorker(fobj, pair.Key, pair.Key.GetType());
|
SerialiseObjectWorker(fobj, pair.Key, pair.Key.GetType(), options);
|
||||||
SerialiseObjectWorker(fobj, pair.Value, pair.Value.GetType());
|
SerialiseObjectWorker(fobj, pair.Value, pair.Value.GetType(), options);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var specialmethod = typeof(Whoa).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).FirstOrDefault(m =>
|
|
||||||
{
|
|
||||||
var attr = m.GetCustomAttributes(typeof(SpecialSerialiserAttribute), false).SingleOrDefault() as SpecialSerialiserAttribute;
|
|
||||||
if (attr == null)
|
|
||||||
return false;
|
|
||||||
return attr.t == t;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (specialmethod != null)
|
|
||||||
{
|
|
||||||
specialmethod.Invoke(null, new object[] { fobj, obj });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
write.Write(obj); // Will fail if not an integral type
|
write.Write(obj); // Will fail if not a primitive type
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -391,12 +511,15 @@ namespace Whoa
|
||||||
|
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
{
|
{
|
||||||
write.Write(-1);
|
write.Write((int)SpecialSizes.Null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.HasFlag(SerialisationOptions.RequireSerializable) && t.GetCustomAttributes(typeof(SerializableAttribute), false).SingleOrDefault() == null)
|
||||||
|
throw new SerializationException($"{t} is not serialisable.");
|
||||||
|
|
||||||
var bools = new List<bool>();
|
var bools = new List<bool>();
|
||||||
var members = Members(t);
|
var members = Members(t, options);
|
||||||
write.Write(members.Count());
|
write.Write(members.Count());
|
||||||
|
|
||||||
foreach (dynamic member in members)
|
foreach (dynamic member in members)
|
||||||
|
@ -413,7 +536,7 @@ namespace Whoa
|
||||||
{
|
{
|
||||||
var val = member.GetValue(obj) as IEnumerable<bool>;
|
var val = member.GetValue(obj) as IEnumerable<bool>;
|
||||||
if (val == null)
|
if (val == null)
|
||||||
write.Write(-1);
|
write.Write((int)SpecialSizes.Null);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write.Write(val.Count());
|
write.Write(val.Count());
|
||||||
|
@ -423,39 +546,56 @@ namespace Whoa
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dynamic val = member.GetValue(obj);
|
dynamic val = member.GetValue(obj);
|
||||||
SerialiseObjectWorker(fobj, val, memt);
|
SerialiseObjectWorker(fobj, val, memt, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteBitfield(fobj, bools);
|
WriteBitfield(fobj, bools);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SerialiseObject(Stream fobj, dynamic obj, Type t)
|
public static void SerialiseObject(Type t, Stream fobj, dynamic obj, SerialisationOptions options = SerialisationOptions.None)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SerialiseObjectWorker(fobj, obj, t);
|
SerialiseObjectWorker(fobj, obj, t, options);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ex.Data.Add("Whoa: Type", t);
|
try
|
||||||
ex.Data.Add("Whoa: Object", obj);
|
{
|
||||||
|
ex.Data.Add("Whoa: Type", t);
|
||||||
|
ex.Data.Add("Whoa: Object", obj);
|
||||||
|
}
|
||||||
|
catch // Stifle this exception and throw the important one
|
||||||
|
{
|
||||||
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static object DeserialiseObject(Type t, Stream fobj)
|
[Obsolete("This argument order is weird.")]
|
||||||
|
public static void SerialiseObject(Stream fobj, dynamic obj, Type t)
|
||||||
|
{
|
||||||
|
SerialiseObject(t, fobj, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object DeserialiseObject(Type t, Stream fobj, SerialisationOptions options = SerialisationOptions.None)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return DeserialiseObjectWorker(t, fobj);
|
return DeserialiseObjectWorker(t, fobj, options);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
ex.Data.Add("Whoa: Type", t);
|
try
|
||||||
|
{
|
||||||
|
ex.Data.Add("Whoa: Type", t);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,10 +39,13 @@
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Numerics" />
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ISpecialSerialiser.cs" />
|
||||||
<Compile Include="OrderAttribute.cs" />
|
<Compile Include="OrderAttribute.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="SerialisationMode.cs" />
|
||||||
<Compile Include="Whoa.cs" />
|
<Compile Include="Whoa.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
|
Loading…
Reference in a new issue