-
-
Save heaths/d105148428fe09a2631322b656f04ebb to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="utf-8"?> | |
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> | |
<CodeSnippet Format="1.0.0"> | |
<Header> | |
<Title>Enumeration-style Structure</Title> | |
<Keywords> | |
<Keyword>enum</Keyword> | |
</Keywords> | |
<Shortcut>enumStruct</Shortcut> | |
</Header> | |
<Snippet> | |
<Code Language="CSharp"><![CDATA[ | |
public readonly struct $typeName$ : IEquatable<$typeName$> | |
{ | |
private readonly string _value; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="$typeName$"/> structure. | |
/// </summary> | |
/// <param name="value">The string value of the instance.</param> | |
public $typeName$(string value) | |
{ | |
_value = value ?? throw new ArgumentNullException(nameof(value)); | |
} | |
// TODO: Define internal or private string constants here if you want to use them in switch statements: | |
// internal const string s_value1 = "value1"; | |
// TODO: Define well-known values here (use constant values from above if defined): | |
// public static $typeName$ Value1 { get; } = new $typeName$(s_value1); | |
// public static $typeName$ Value2 { get; } = new $typeName$("value2"); | |
/// <summary> | |
/// Determines if two <see cref="$typeName$"/> values are the same. | |
/// </summary> | |
/// <param name="left">The first <see cref="$typeName$"/> to compare.</param> | |
/// <param name="right">The second <see cref="$typeName$"/> to compare.</param> | |
/// <returns>True if <paramref name="left"/> and <paramref name="right"/> are the same; otherwise, false.</returns> | |
public static bool operator ==($typeName$ left, $typeName$ right) => left.Equals(right); | |
/// <summary> | |
/// Determines if two <see cref="$typeName$"/> values are different. | |
/// </summary> | |
/// <param name="left">The first <see cref="$typeName$"/> to compare.</param> | |
/// <param name="right">The second <see cref="$typeName$"/> to compare.</param> | |
/// <returns>True if <paramref name="left"/> and <paramref name="right"/> are different; otherwise, false.</returns> | |
public static bool operator !=($typeName$ left, $typeName$ right) => !left.Equals(right); | |
/// <summary> | |
/// Converts a string to a <see cref="$typeName$"/>. | |
/// </summary> | |
/// <param name="value">The string value to convert.</param> | |
public static implicit operator $typeName$(string value) => new $typeName$(value); | |
/// <inheritdoc/> | |
[EditorBrowsable(EditorBrowsableState.Never)] | |
public override bool Equals(object obj) => obj is $typeName$ other && Equals(other); | |
/// <inheritdoc/> | |
public bool Equals($typeName$ other) => string.Equals(_value, other._value, StringComparison.Ordinal); | |
/// <inheritdoc/> | |
[EditorBrowsable(EditorBrowsableState.Never)] | |
public override int GetHashCode() => _value?.GetHashCode() ?? 0; | |
/// <inheritdoc/> | |
public override string ToString() => _value; | |
// TODO: If you need to attach other data to the struct value, follow the pattern below: | |
// internal int GetNumberValue() => _value switch | |
// { | |
// s_value1 => 1, | |
// _ => 0, | |
// }; | |
} | |
]]> | |
</Code> | |
<Declarations> | |
<Literal Editable="true"> | |
<ID>typeName</ID> | |
<ToolTip>The name of the structure you want to define.</ToolTip> | |
</Literal> | |
</Declarations> | |
<Imports> | |
<Import> | |
<Namespace>System</Namespace> | |
</Import> | |
<Import> | |
<Namespace>System.ComponentModel</Namespace> | |
</Import> | |
</Imports> | |
</Snippet> | |
</CodeSnippet> | |
</CodeSnippets> |
I guess I wouldn't need this for any string concatenation, but just as a repository for the different values I am setting. A HasFlag method similar to Flags enum would be nice.
But that really only makes sense for a flags-enum, which is the only case in which you'd define a OR/concatenation operator; otherwise, it's just a comparison you already get with the equality operator. Do you have another example in mind?
Yeah, I just meant that it didn't matter how the string of values was represented, just as long as I could get which flags were set.
This would be for a permissions enum-style struct.
It's all connected, though. If you expect that the "enum" might be modified often and contain many keys, storing the value as a concatenation vs. array of values that we format when needed may be better in some cases or other. It's certainly something we can add to the definition and example (perhaps as another example for clarity).
A concatenation of values (perhaps through a StringBuilder
might be better since a HasFlags
implementation could use IndexOf
to see if a value is set, vs. loop through an array doing string comparisons. Last I checked, IndexOf
was more efficient - but probably not by much.
Or a HashSet?
Typically the overhead of bucketing isn't worth it until you have sufficient number of elements. In fact, there are types in .NET that use one implementation or another as private implementation depending on a threshold.
Currently, no. It came up once, but we never came to resolution since we didn't actually know of any need at the time. One thing we considered as adding an
|
operator that would concatenate however appropriate (e.g. "," or "+" separated). Would love feedback or any input on this otherwise.