javascript - ¿C# tiene un tipo símbolo?
JavaScript (ES2015) introduce el nuevo tipo Symbol, que difiere de las cadenas en que los símbolos se comparan por referencia, mientras que las cadenas se comparan por valor.
¿Tiene C# algo comparable?
Respuesta #1
object en C# cumple muchas de las mismas propiedades de symbol en ECMAScript 6.
Considera el código de JavaScript:
const MY_KEY = Symbol();
let obj = {};
obj[MY_KEY] = 123;
console.log(obj[MY_KEY]); // 123
En C#, esto se puede representar de manera similar como:
readonly object MyKey = new object();
// ...
var obj = new Dictionary<object, int>() {{MyKey, 123}};
Console.WriteLine(obj[MyKey]); // 123
Sin embargo, el tipo Symbol abarca funcionalidades adicionales: un registro global, claves bien conocidas y la funcionalidad de etiquetar símbolos con descripciones (especificación ES2015, § 19.4). Esta funcionalidad se puede reproducir en gran medida en C# 6 como un envoltorio simple:
class Symbol : IEquatable<Symbol>
{
private object o = new object();
public string Description { get; }
public Symbol(string description)
{
Description = description;
}
public Symbol() : this(null) { }
public bool Equals(Symbol other) => other?.o == o;
public static bool operator == (Symbol o1, Symbol o2) =>
EqualityComparer<Symbol>.Default.Equals(o1, o2);
public static bool operator !=(Symbol o1, Symbol o2) => !(o1 == o2);
public override int GetHashCode()
{
return o.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Symbol);
}
public override string ToString() => $"symbol({Description})";
// static methods to support symbol registry
private static Dictionary<string, Symbol> GlobalSymbols =
new Dictionary<string, Symbol>(StringComparer.Ordinal);
public static Symbol For(string key) =>
GlobalSymbols.ContainsKey(key) ?
GlobalSymbols[key] :
GlobalSymbols[key] = new Symbol(key);
public static string KeyFor(Symbol s) =>
GlobalSymbols.FirstOrDefault(a => a.Value == s).Key; // returns null if s not defined
// Well-known ECMAScript symbols
private const string ns = "Symbol.";
public static Symbol HasInstance => For(ns + "hasInstance");
public static Symbol IsConcatSpreadable => For(ns + "isConcatSpreadable");
public static Symbol Iterator => For(ns + "iterator");
public static Symbol Match => For(ns + "match");
public static Symbol Replace => For(ns + "replace");
public static Symbol Search => For(ns + "search");
public static Symbol Species => For(ns + "species");
public static Symbol Split => For(ns + "split");
public static Symbol ToPrimitive => For(ns + "toPrimitive");
public static Symbol ToStringTag => For(ns + "toStringTag");
public static Symbol Unscopables => For(ns + "unscopables");
}
El comportamiento resultante está en línea con el comportamiento esperado de ECMAScript:
Symbol a = new Symbol();
Symbol b = new Symbol("A");
Symbol c = new Symbol("A");
Symbol d = c;
var dict = new Dictionary<object, int>() { { c, 42 } };
Symbol e = Symbol.For("X");
Symbol f = Symbol.For("X");
Symbol g = Symbol.For("Y");
Console.WriteLine(a == b); // false
Console.WriteLine(b == c); // false
Console.WriteLine(c == d); // true
Console.WriteLine(dict[d]); // 42
Console.WriteLine(e == f); // true
Console.WriteLine(f == g); // false
Console.WriteLine(Symbol.For("X") == e); // true
Console.WriteLine(Symbol.KeyFor(e) == "X"); // true
Console.WriteLine(Symbol.Unscopables.Description); // Symbol.unscopables
