【发布时间】:2021-02-03 03:51:48
【问题描述】:
我需要一个像Tuple 或KeyValuePair 这样的类型,并且可以选择设置它的值(可变类型)。
现有泛型有什么想法可以满足这些需求吗?
(在我看来,字典对我来说有点矫枉过正)
我也可以编写自己的类,但我希望已经实现了一些可变类型的KeyValuePair。
【问题讨论】:
标签: c# generics data-structures key-value
我需要一个像Tuple 或KeyValuePair 这样的类型,并且可以选择设置它的值(可变类型)。
现有泛型有什么想法可以满足这些需求吗?
(在我看来,字典对我来说有点矫枉过正)
我也可以编写自己的类,但我希望已经实现了一些可变类型的KeyValuePair。
【问题讨论】:
标签: c# generics data-structures key-value
使用可变变量的问题在于,您可以很容易地最终引用同一个元组多次,当您在一个地方更改值时,它也会在您不期望的其他地方更改。因此,如果您确实使用可变元组,则必须非常严格地在适当的位置克隆元组,例如将其放入集合中。
但是可变元组看起来像这样:
public class MutableTuple<T1, T2> {
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
public MutableTuple(T1 item1, T2 item2) {
Item1 = item1;
Item2 = item2;
}
}
【讨论】:
public class MutableKeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
就是这样。
【讨论】:
不,没有。除非你认为object[] 是其中之一:-)
请注意,实现MutableTuple<T1, ...> 非常简单。
MutableTuple<T1, T2, T3> 的完整实现,几乎等同于 Tuple<T1, T2, T3>(各种接口是公开实现的,而不是私有实现的)(部分基于 Tuple<> 的 Mono 实现)
public static class MutableTuple
{
public static MutableTuple<T1, T2, T3> Create<T1, T2, T3>(T1 item1, T2 item2, T3 item3)
{
return new MutableTuple<T1, T2, T3>(item1, item2, item3);
}
}
[Serializable]
public class MutableTuple<T1, T2, T3> : IComparable, IStructuralEquatable, IStructuralComparable
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
public T3 Item3 { get; set; }
public MutableTuple(T1 item1, T2 item2, T3 item3)
{
this.Item1 = item1;
this.Item2 = item2;
this.Item3 = item3;
}
public override bool Equals(object obj)
{
return this.Equals(obj, EqualityComparer<object>.Default);
}
public override int GetHashCode()
{
return this.GetHashCode(EqualityComparer<object>.Default);
}
public override string ToString()
{
var sb = new StringBuilder();
sb.Append(this.Item1);
sb.Append(", ");
sb.Append(this.Item2);
sb.Append(", ");
sb.Append(this.Item3);
sb.Append(")");
return sb.ToString();
}
public int CompareTo(object obj)
{
return this.CompareTo(obj, Comparer<object>.Default);
}
public bool Equals(object obj, IEqualityComparer comparer)
{
if (obj == null)
{
return false;
}
var tuple = obj as MutableTuple<T1, T2, T3>;
return tuple != null && (comparer.Equals(this.Item1, tuple.Item1) && comparer.Equals(this.Item2, tuple.Item2)) && comparer.Equals(this.Item3, tuple.Item3);
}
public int GetHashCode(IEqualityComparer comparer)
{
unchecked
{
int hash = 17;
hash = (hash * 23) + comparer.GetHashCode(this.Item1);
hash = (hash * 23) + comparer.GetHashCode(this.Item2);
hash = (hash * 23) + comparer.GetHashCode(this.Item3);
return hash;
}
}
public int CompareTo(object obj, IComparer comparer)
{
if (obj == null)
{
return 1;
}
var other = obj as MutableTuple<T1, T2, T3>;
if (other == null)
{
throw new ArgumentException();
}
int res = comparer.Compare(this.Item1, other.Item1);
if (res != 0)
{
return res;
}
res = comparer.Compare(this.Item2, other.Item2);
if (res != 0)
{
return res;
}
res = comparer.Compare(this.Item3, other.Item3);
return res;
}
}
【讨论】:
DictionaryEntry,这是一个可变对,但它有两个问题:(1)它不是泛型/类型安全的。 (2) 是可变值类型。
struct :-) 对于 Tuple,他们非常努力地考虑并选择了classes。第二个(它是一个可变值类型)是一个特性,而不是一个错误:-)
Mutuple 会是一个更好的命名:D
IStructuralEquatable 就是这样完成的。 2)可能是的,但这取决于子字符串的长度。例如,如果this.Item1 == this.Item2 == this.Item3 == "" 那么简单的字符串连接会更好。但请记住,这是一个代码示例。您必须为各种数量的参数实现它(Tuple<...> 最多可达 8 个)。使用 8 个参数,StringBuilder 会更快。 3)我不是很擅长命名。当我工作时,我尽量让我的同事或我的老板选择名字。
IStructuralEquatable 可能是这样,但在不改变结果行为的情况下以通用方式处理 public override bool Equals(object obj) 不是更好吗?但我看到框架本身实现了你所展示的:(。3)我是在开玩笑:)