Skip to content

Instantly share code, notes, and snippets.

@tormodfj
Last active July 17, 2019 07:25
Show Gist options
  • Save tormodfj/39cbcc5ef75ea229ad4a5f071316ee61 to your computer and use it in GitHub Desktop.
Save tormodfj/39cbcc5ef75ea229ad4a5f071316ee61 to your computer and use it in GitHub Desktop.
Helper class for working with Entity Tags (ETags) in Web APIs
using System;
using System.Globalization;
namespace Common
{
/// <summary>
/// A value type representing an Entity Tag (ETag).
/// </summary>
public struct ETag : IFormattable
{
/// <summary>Represents an empty <see cref="ETag"/>. This field is read-only.</summary>
public static readonly ETag Empty = new ETag(string.Empty);
private readonly string stringValue;
private ETag(string stringValue)
=> this.stringValue = stringValue ?? string.Empty;
/// <summary>Indicates whether the value of the <see cref="ETag"/> is an integer.</summary>
public bool IsInt32
=> int.TryParse(stringValue, out var _);
/// <summary>Creates an <see cref="ETag"/> from an <see cref="int"/>.</summary>
public static ETag FromInt32(int value)
=> new ETag(value.ToString());
/// <summary>Creates an <see cref="ETag"/> from a <see cref="string"/>.</summary>
public static ETag FromString(string value)
=> new ETag(value);
/// <summary>Creates an <see cref="ETag"/> from a header value (enclosed in quotes).</summary>
public static ETag FromHeaderValue(string value)
=> new ETag(value.Trim('"'));
/// <summary>Returns a value indicating whether this instance is equal to a specified object</summary>
public override bool Equals(object obj)
=> obj is ETag other ? this == other : false;
/// <summary>Returns the hash code for this <see cref="ETag"/>.</summary>
public override int GetHashCode()
=> stringValue.GetHashCode();
/// <summary>Converts the <see cref="ETag"/> to an <see cref="int"/>.</summary>
public int ToInt32()
=> int.Parse(stringValue);
/// <summary>Converts the <see cref="ETag"/> to a <see cref="string"/>.</summary>
public override string ToString()
=> ToString("G");
/// <summary>
/// Formats the value of the current <see cref="ETag"/> using the specified format.
/// Format "G" yields the general string representation. Format "E" yields the HTTP
/// ETag format.
/// </summary>
public string ToString(string format)
=> ToString(format, CultureInfo.InvariantCulture);
/// <summary>
/// Formats the value of the current <see cref="ETag"/> using the specified format.
/// Format "G" yields the general string representation. Format "E" yields the HTTP
/// ETag format.
/// </summary>
public string ToString(string format, IFormatProvider formatProvider)
=> Format(format);
/// <summary>Determines whether two specified <see cref="ETag"/>s have the same value.</summary>
public static bool operator ==(ETag x, ETag y)
=> x.stringValue == y.stringValue;
/// <summary>Determines whether two specified <see cref="ETag"/>s have different values.</summary>
public static bool operator !=(ETag x, ETag y)
=> x.stringValue != y.stringValue;
/// <summary>Provides implicit casting from <see cref="ETag"/> to <see cref="string"/>.</summary>
public static implicit operator string(ETag t)
=> t.stringValue;
/// <summary>Provides implicit casting from <see cref="string"/> to <see cref="ETag"/>.</summary>
public static implicit operator ETag(string s)
=> FromString(s);
/// <summary>Provides implicit casting from <see cref="ETag"/> to <see cref="int"/>.</summary>
public static implicit operator int(ETag t)
=> t.ToInt32();
/// <summary>Provides implicit casting from <see cref="int"/> to <see cref="ETag"/>.</summary>
public static implicit operator ETag(int i)
=> FromInt32(i);
private string Format(string format)
{
if (string.IsNullOrEmpty(format)) format = "G";
switch (format.ToUpperInvariant())
{
case "G":
return stringValue;
case "E":
return $@"""{stringValue}""";
default:
throw new FormatException($"The {format} format string is not supported.");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment