Skip to content

Instantly share code, notes, and snippets.

@niemyjski

niemyjski/test.cs

Created Dec 20, 2019
Embed
What would you like to do?
json.net system.version bug with .net core 3.1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Exceptionless.Core.Extensions;
using Exceptionless.Core.Models;
using Exceptionless.Core.Models.Data;
using Exceptionless.Serializer;
using Foundatio.Serializer;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
using Xunit.Abstractions;
namespace Exceptionless.Tests {
public class VersionSerializerTest : TestWithServices {
public VersionSerializerTest(ServicesFixture fixture, ITestOutputHelper output) : base(fixture, output) { }
public class TestModel {
public System.Version Version { get; set; }
public System.Version2 Version2 { get; set; }
}
[Fact]
public void CanDeserializeWebHook2() {
var model = new TestModel {
Version = new Version(1, 0),
Version2 = new Version2(1, 0)
};
string json = JsonConvert.SerializeObject(model, new JsonSerializerSettings());
_logger.LogInformation(json);
}
}
}
namespace System
{
// A Version object contains four hierarchical numeric components: major, minor,
// build and revision. Build and revision may be unspecified, which is represented
// internally as a -1. By definition, an unspecified component matches anything
// (both unspecified and specified), and an unspecified component is "less than" any
// specified component.
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class Version2 : ICloneable, IComparable, IComparable<Version2>, IEquatable<Version2>//, ISpanFormattable
{
// AssemblyName depends on the order staying the same
private readonly int _Major; // Do not rename (binary serialization)
private readonly int _Minor; // Do not rename (binary serialization)
private readonly int _Build = -1; // Do not rename (binary serialization)
private readonly int _Revision = -1; // Do not rename (binary serialization)
public Version2(int major, int minor, int build, int revision)
{
_Major = major;
_Minor = minor;
_Build = build;
_Revision = revision;
}
public Version2(int major, int minor, int build)
{
// if (major < 0)
// throw new ArgumentOutOfRangeException(nameof(major), SR.ArgumentOutOfRange_Version);
// if (minor < 0)
// throw new ArgumentOutOfRangeException(nameof(minor), SR.ArgumentOutOfRange_Version);
// if (build < 0)
// throw new ArgumentOutOfRangeException(nameof(build), SR.ArgumentOutOfRange_Version);
_Major = major;
_Minor = minor;
_Build = build;
}
public Version2(int major, int minor)
{
// if (major < 0)
// throw new ArgumentOutOfRangeException(nameof(major), SR.ArgumentOutOfRange_Version);
// if (minor < 0)
// throw new ArgumentOutOfRangeException(nameof(minor), SR.ArgumentOutOfRange_Version);
_Major = major;
_Minor = minor;
}
public Version2(String version)
{
Version v = Version.Parse(version);
_Major = v.Major;
_Minor = v.Minor;
_Build = v.Build;
_Revision = v.Revision;
}
public Version2()
{
_Major = 0;
_Minor = 0;
}
private Version2(Version2 version)
{
Debug.Assert(version != null);
_Major = version._Major;
_Minor = version._Minor;
_Build = version._Build;
_Revision = version._Revision;
}
public object Clone()
{
return new Version2(this);
}
// Properties for setting and getting version numbers
public int Major
{
get { return _Major; }
}
public int Minor
{
get { return _Minor; }
}
public int Build
{
get { return _Build; }
}
public int Revision
{
get { return _Revision; }
}
public short MajorRevision
{
get { return (short)(_Revision >> 16); }
}
public short MinorRevision
{
get { return (short)(_Revision & 0xFFFF); }
}
public int CompareTo(Object version)
{
if (version == null)
{
return 1;
}
Version2 v = version as Version2;
if (v == null)
{
// throw new ArgumentException(SR.Arg_MustBeVersion);
}
return CompareTo(v);
}
public int CompareTo(Version2 value)
{
return
object.ReferenceEquals(value, this) ? 0 :
object.ReferenceEquals(value, null) ? 1 :
_Major != value._Major ? (_Major > value._Major ? 1 : -1) :
_Minor != value._Minor ? (_Minor > value._Minor ? 1 : -1) :
_Build != value._Build ? (_Build > value._Build ? 1 : -1) :
_Revision != value._Revision ? (_Revision > value._Revision ? 1 : -1) :
0;
}
public override bool Equals(Object obj)
{
return Equals(obj as Version2);
}
public bool Equals(Version2 obj)
{
return object.ReferenceEquals(obj, this) ||
(!object.ReferenceEquals(obj, null) &&
_Major == obj._Major &&
_Minor == obj._Minor &&
_Build == obj._Build &&
_Revision == obj._Revision);
}
public override int GetHashCode()
{
// Let's assume that most version numbers will be pretty small and just
// OR some lower order bits together.
int accumulator = 0;
accumulator |= (_Major & 0x0000000F) << 28;
accumulator |= (_Minor & 0x000000FF) << 20;
accumulator |= (_Build & 0x000000FF) << 12;
accumulator |= (_Revision & 0x00000FFF);
return accumulator;
}
public override string ToString() =>
ToString(DefaultFormatFieldCount);
public string ToString(int fieldCount) => fieldCount == 0 ? string.Empty : fieldCount == 1 ? _Major.ToString() : "";
//StringBuilderCache.GetStringAndRelease(ToCachedStringBuilder(fieldCount));
public bool TryFormat(Span<char> destination, out int charsWritten) =>
TryFormat(destination, DefaultFormatFieldCount, out charsWritten);
public bool TryFormat(Span<char> destination, int fieldCount, out int charsWritten)
{
if (fieldCount == 0)
{
charsWritten = 0;
return true;
}
else if (fieldCount == 1)
{
return _Major.TryFormat(destination, out charsWritten);
}
StringBuilder sb = ToCachedStringBuilder(fieldCount);
if (sb.Length <= destination.Length)
{
sb.CopyTo(0, destination, sb.Length);
//StringBuilderCache.Release(sb);
charsWritten = sb.Length;
return true;
}
//StringBuilderCache.Release(sb);
charsWritten = 0;
return false;
}
private int DefaultFormatFieldCount =>
_Build == -1 ? 2 :
_Revision == -1 ? 3 :
4;
private StringBuilder ToCachedStringBuilder(int fieldCount)
{
// Note: As we always have positive numbers then it is safe to convert the number to string
// regardless of the current culture as we'll not have any punctuation marks in the number.
if (fieldCount == 2)
{
StringBuilder sb = new StringBuilder();
sb.Append(_Major);
sb.Append('.');
sb.Append(_Minor);
return sb;
}
else
{
if (_Build == -1)
{
throw new ArgumentException("", nameof(fieldCount));
}
if (fieldCount == 3)
{
StringBuilder sb = new StringBuilder();
sb.Append(_Major);
sb.Append('.');
sb.Append(_Minor);
sb.Append('.');
sb.Append(_Build);
return sb;
}
if (_Revision == -1)
{
throw new ArgumentException("", nameof(fieldCount));
}
if (fieldCount == 4)
{
StringBuilder sb = new StringBuilder();
sb.Append(_Major);
sb.Append('.');
sb.Append(_Minor);
sb.Append('.');
sb.Append(_Build);
sb.Append('.');
sb.Append(_Revision);
return sb;
}
throw new ArgumentException("", nameof(fieldCount));
}
}
public static Version Parse(string input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
return ParseVersion(input.AsSpan(), throwOnFailure: true);
}
public static Version Parse(ReadOnlySpan<char> input) =>
ParseVersion(input, throwOnFailure: true);
public static bool TryParse(string input, out Version result)
{
if (input == null)
{
result = null;
return false;
}
return (result = ParseVersion(input.AsSpan(), throwOnFailure: false)) != null;
}
public static bool TryParse(ReadOnlySpan<char> input, out Version result) =>
(result = ParseVersion(input, throwOnFailure: false)) != null;
private static Version ParseVersion(ReadOnlySpan<char> input, bool throwOnFailure)
{
// Find the separator between major and minor. It must exist.
int majorEnd = input.IndexOf('.');
if (majorEnd < 0)
{
if (throwOnFailure) throw new ArgumentException("", nameof(input));
return null;
}
// Find the ends of the optional minor and build portions.
// We musn't have any separators after build.
int buildEnd = -1;
int minorEnd = input.Slice(majorEnd + 1).IndexOf('.');
if (minorEnd != -1)
{
minorEnd += (majorEnd + 1);
buildEnd = input.Slice(minorEnd + 1).IndexOf('.');
if (buildEnd != -1)
{
buildEnd += (minorEnd + 1);
if (input.Slice(buildEnd + 1).IndexOf('.') != -1)
{
if (throwOnFailure) throw new ArgumentException("", nameof(input));
return null;
}
}
}
int minor, build, revision;
// Parse the major version
if (!TryParseComponent(input.Slice(0, majorEnd), nameof(input), throwOnFailure, out int major))
{
return null;
}
if (minorEnd != -1)
{
// If there's more than a major and minor, parse the minor, too.
if (!TryParseComponent(input.Slice(majorEnd + 1, minorEnd - majorEnd - 1), nameof(input), throwOnFailure, out minor))
{
return null;
}
if (buildEnd != -1)
{
// major.minor.build.revision
return
TryParseComponent(input.Slice(minorEnd + 1, buildEnd - minorEnd - 1), nameof(build), throwOnFailure, out build) &&
TryParseComponent(input.Slice(buildEnd + 1), nameof(revision), throwOnFailure, out revision) ?
new Version(major, minor, build, revision) :
null;
}
else
{
// major.minor.build
return TryParseComponent(input.Slice(minorEnd + 1), nameof(build), throwOnFailure, out build) ?
new Version(major, minor, build) :
null;
}
}
else
{
// major.minor
return TryParseComponent(input.Slice(majorEnd + 1), nameof(input), throwOnFailure, out minor) ?
new Version(major, minor) :
null;
}
}
private static bool TryParseComponent(ReadOnlySpan<char> component, string componentName, bool throwOnFailure, out int parsedComponent)
{
if (throwOnFailure)
{
if ((parsedComponent = int.Parse(component, NumberStyles.Integer, CultureInfo.InvariantCulture)) < 0)
{
throw new ArgumentOutOfRangeException(componentName, "");
}
return true;
}
return int.TryParse(component, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsedComponent) && parsedComponent >= 0;
}
public static bool operator ==(Version2 v1, Version2 v2)
{
if (Object.ReferenceEquals(v1, null))
{
return Object.ReferenceEquals(v2, null);
}
return v1.Equals(v2);
}
public static bool operator !=(Version2 v1, Version2 v2)
{
return !(v1 == v2);
}
public static bool operator <(Version2 v1, Version2 v2)
{
if ((Object)v1 == null)
throw new ArgumentNullException(nameof(v1));
return (v1.CompareTo(v2) < 0);
}
public static bool operator <=(Version2 v1, Version2 v2)
{
if ((Object)v1 == null)
throw new ArgumentNullException(nameof(v1));
return (v1.CompareTo(v2) <= 0);
}
public static bool operator >(Version2 v1, Version2 v2)
{
return (v2 < v1);
}
public static bool operator >=(Version2 v1, Version2 v2)
{
return (v2 <= v1);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment