Implemented IEquatable interface for tags
Error checking names/types with list types is down performed within the abstract base list itself when added, not during serialization
This commit is contained in:
parent
68dd7aa011
commit
e728f47790
|
@ -21,6 +21,8 @@ namespace SharpNBT
|
|||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
||||
public CompoundTag([CanBeNull] string name) : base(TagType.Compound, name)
|
||||
{
|
||||
NamedChildren = true;
|
||||
RequiredType = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -28,8 +30,9 @@ namespace SharpNBT
|
|||
/// </summary>
|
||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
||||
/// <param name="values">A collection <see cref="Tag"/> objects that are children of this object.</param>
|
||||
public CompoundTag([CanBeNull] string name, [NotNull] IEnumerable<Tag> values) : base(TagType.Compound, name, values)
|
||||
public CompoundTag([CanBeNull] string name, [NotNull] IEnumerable<Tag> values) : this(name)
|
||||
{
|
||||
AddRange(values);
|
||||
}
|
||||
|
||||
/// <summary>Returns a string that represents the current object.</summary>
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace SharpNBT
|
|||
/// <param name="childType">A constant describing the NBT type for children in this tag.</param>
|
||||
public ListTag([CanBeNull] string name, TagType childType) : base(TagType.List, name)
|
||||
{
|
||||
RequiredType = childType;
|
||||
NamedChildren = false;
|
||||
ChildType = childType;
|
||||
}
|
||||
|
||||
|
@ -36,9 +38,8 @@ namespace SharpNBT
|
|||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
||||
/// <param name="childType">A constant describing the NBT type for children in this tag.</param>
|
||||
/// <param name="children">A collection of values to include in this tag.</param>
|
||||
public ListTag([CanBeNull] string name, TagType childType, [NotNull][ItemNotNull] IEnumerable<Tag> children) : base(TagType.List, name)
|
||||
public ListTag([CanBeNull] string name, TagType childType, [NotNull][ItemNotNull] IEnumerable<Tag> children) : this(name, childType)
|
||||
{
|
||||
ChildType = childType;
|
||||
AddRange(children);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace SharpNBT
|
|||
/// Abstract base class that all NBT tags inherit from.
|
||||
/// </summary>
|
||||
[PublicAPI][DataContract][KnownType("GetKnownTypes")]
|
||||
public abstract class Tag
|
||||
public abstract class Tag : IEquatable<Tag>
|
||||
{
|
||||
private static IEnumerable<Type> GetKnownTypes()
|
||||
{
|
||||
|
@ -130,6 +130,48 @@ namespace SharpNBT
|
|||
stream.Flush();
|
||||
return Encoding.UTF8.GetString(stream.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
|
||||
/// <param name="other">An object to compare with this object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the current object is equal to the <paramref name="other" /> parameter; otherwise, <see langword="false" />.</returns>
|
||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.IEquatable-1.Equals?view=netstandard-2.1">`IEquatable.Equals` on docs.microsoft.com</a></footer>
|
||||
public bool Equals(Tag other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Type == other.Type && Name == other.Name;
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the specified object is equal to the current object.</summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the specified object is equal to the current object; otherwise, <see langword="false" />.</returns>
|
||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Object.Equals?view=netstandard-2.1">`Object.Equals` on docs.microsoft.com</a></footer>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((Tag)obj);
|
||||
}
|
||||
|
||||
/// <summary>Serves as the default hash function.</summary>
|
||||
/// <returns>A hash code for the current object.</returns>
|
||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Object.GetHashCode?view=netstandard-2.1">`Object.GetHashCode` on docs.microsoft.com</a></footer>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// ReSharper disable NonReadonlyMemberInGetHashCode
|
||||
return ((int)Type * 373) ^ (Name != null ? Name.GetHashCode() : 0);
|
||||
// ReSharper restore NonReadonlyMemberInGetHashCode
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(Tag left, Tag right) => Equals(left, right);
|
||||
|
||||
public static bool operator !=(Tag left, Tag right) => !Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -137,7 +179,7 @@ namespace SharpNBT
|
|||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value the tag represents.</typeparam>
|
||||
[PublicAPI][DataContract]
|
||||
public abstract class Tag<T> : Tag
|
||||
public abstract class Tag<T> : Tag, IEquatable<Tag<T>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the tag.
|
||||
|
@ -163,5 +205,47 @@ namespace SharpNBT
|
|||
buffer.Append(indent);
|
||||
buffer.AppendLine(ToString());
|
||||
}
|
||||
|
||||
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
|
||||
/// <param name="other">An object to compare with this object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the current object is equal to the <paramref name="other" /> parameter; otherwise, <see langword="false" />.</returns>
|
||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.IEquatable-1.Equals?view=netstandard-2.1">`IEquatable.Equals` on docs.microsoft.com</a></footer>
|
||||
public bool Equals(Tag<T> other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return base.Equals(other) && EqualityComparer<T>.Default.Equals(Value, other.Value);
|
||||
}
|
||||
|
||||
/// <summary>Determines whether the specified object is equal to the current object.</summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true" /> if the specified object is equal to the current object; otherwise, <see langword="false" />.</returns>
|
||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Object.Equals?view=netstandard-2.1">`Object.Equals` on docs.microsoft.com</a></footer>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
return Equals((Tag<T>)obj);
|
||||
}
|
||||
|
||||
/// <summary>Serves as the default hash function.</summary>
|
||||
/// <returns>A hash code for the current object.</returns>
|
||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Object.GetHashCode?view=netstandard-2.1">`Object.GetHashCode` on docs.microsoft.com</a></footer>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// ReSharper disable NonReadonlyMemberInGetHashCode
|
||||
return (base.GetHashCode() * 421) ^ EqualityComparer<T>.Default.GetHashCode(Value);
|
||||
// ReSharper restore NonReadonlyMemberInGetHashCode
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator ==(Tag<T> left, Tag<T> right) => Equals(left, right);
|
||||
|
||||
public static bool operator !=(Tag<T> left, Tag<T> right) => !Equals(left, right);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Serialization;
|
||||
using JetBrains.Annotations;
|
||||
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
|
||||
|
@ -10,8 +11,11 @@ namespace SharpNBT
|
|||
/// Base class for tags that contain a collection of other <see cref="Tag"/> objects and can be enumerated.
|
||||
/// </summary>
|
||||
[PublicAPI][DataContract]
|
||||
public abstract class TagContainer : EnumerableTag<Tag>
|
||||
public abstract class TagContainer : EnumerableTag<Tag>
|
||||
{
|
||||
protected bool NamedChildren;
|
||||
protected TagType? RequiredType;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TagContainer"/>.
|
||||
/// </summary>
|
||||
|
@ -38,7 +42,7 @@ namespace SharpNBT
|
|||
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
|
||||
public sealed override void Add(Tag item)
|
||||
{
|
||||
base.Add(item ?? throw new ArgumentNullException(nameof(item)));
|
||||
base.Add(AssertConventions(item));
|
||||
item.Parent = this;
|
||||
}
|
||||
|
||||
|
@ -52,7 +56,7 @@ namespace SharpNBT
|
|||
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
|
||||
public sealed override void Insert(int index, Tag item)
|
||||
{
|
||||
base.Insert(index, item ?? throw new ArgumentNullException(nameof(item)));
|
||||
base.Insert(index, AssertConventions(item));
|
||||
item.Parent = this;
|
||||
}
|
||||
|
||||
|
@ -68,7 +72,7 @@ namespace SharpNBT
|
|||
get => base[index];
|
||||
set
|
||||
{
|
||||
base[index] = value ?? throw new ArgumentNullException(nameof(value));
|
||||
base[index] = AssertConventions(value);
|
||||
value.Parent = this;
|
||||
}
|
||||
}
|
||||
|
@ -109,5 +113,30 @@ namespace SharpNBT
|
|||
this[index].Parent = null;
|
||||
base.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs routine checks to ensure that the given <paramref name="tag"/> complies with the NBT standard for this collection type.
|
||||
/// </summary>
|
||||
/// <param name="tag">A <see cref="Tag"/> instance to validate.</param>
|
||||
/// <returns>Returns the <paramref name="tag"/> instance.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="FormatException"></exception>
|
||||
/// <exception cref="ArrayTypeMismatchException"></exception>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected Tag AssertConventions([CanBeNull] Tag tag)
|
||||
{
|
||||
if (tag is null)
|
||||
throw new ArgumentNullException(nameof(tag), "Child tag in collection cannot be null");
|
||||
|
||||
if (NamedChildren && tag.Name is null)
|
||||
throw new FormatException("Children of this collection type must be named.");
|
||||
if (!NamedChildren && tag.Name != null)
|
||||
throw new FormatException("Children of this collection type cannot be named.");
|
||||
|
||||
if (RequiredType.HasValue && RequiredType.Value != tag.Type)
|
||||
throw new ArrayTypeMismatchException("Incorrect tag type added to this collection.");
|
||||
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue