我正在尝试实现可以同时为两种方式建立索引的通用容器:
null
问题是当我尝试为T1和T2使用相同类型的实例时出现编译时错误:
class DoubleIndexer<T1, T2>
{
public T2 this[T1 key] { get => default; set { } }
public T1 this[T2 key] { get => default; set { } }
}
当类型T1和T2不同时,没有问题:
var int_int = new DoubleIndexer<int, int>();
int_int[1] = 13; // CS0121: The call is ambiguous between the following
// methods or properties: 'DoubleIndexer<T1, T2>.this[T1]'
// and 'DoubleIndexer<T1, T2>.this[T2]'
是否有解决此问题的方法,或者我被迫更改了通用类的接口?
答案 0 :(得分:1)
编码器用于Dictionary
代码:
var lookupByIDReversible = new DoubleIndexer<int, string>();
...
lookupByIDReversible[1] = "hello";
lookupByIDReversible.Reverse["hello"] = 1;
您可能会想到一些更好的语言。
我将让您自己实施。
完全另一种方法将利用记录集模式,该模式可以发出保持与集合链接的索引器。该集合是所有索引器的中心。
class Message
{
public int ID;
public int ToUserID;
public int FromUserID
public string MessageBody;
public DateTime UpdatedAt;
}
var messages = new RecordSet<Message>();
messages.AddRange(...);
var byToUserID = messages.IndexBy(r => r.ToUserID);
byToUserID[7].FromUserID = 8; //Found member assignment
byToUserID[9] = byToUserID[10]; //Assignment (probably not desirable)
var byMessageBody = messages.IndexBy(r => r.MessageBody);
byMessageBody["hello"].ToUserID = 11;
byToUserID[12] = new Message() { MessageBody = "test1", ... }; //Where ToUserID in the supplied object will be overwritten.
byMessageBody["test1"].ToUserID == 12; //Evaluates to true
这样做的好处是,您将获得一个语义API,该API应该更具可预测性,但是它也可以扩展到两种以上类型。
答案 1 :(得分:-1)
解决方法可以基于explicit interfaces:
第二版
public interface IDirectIndex<T1, T2>
{
T2 this[T1 key] { get; set; }
}
public interface IInvertedIndex<T1, T2>
{
T1 this[T2 key] { get; set; }
}
internal class DoubleIndexer<T1, T2> : IDirectIndex<T1, T2>, IInvertedIndex<T1, T2>
{
T2 IDirectIndex<T1, T2>.this[T1 key]
{
get => default;
set { Console.WriteLine($"T2 IDirectIndex<T1, T2>.this[T1 key]: {value}"); }
}
T1 IInvertedIndex<T1, T2>.this[T2 key]
{
get => default;
set { Console.WriteLine($"T1 IInvertedIndex<T1, T2>.this[T2 key]: {value}"); }
}
}
测试示例:
var int_string = new DoubleIndexer<int, string>();
((IDirectIndex<int, string>)int_string)[1] = "Hello"; // OK
((IInvertedIndex<int, string>)int_string)["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
((IInvertedIndex<int, byte>)int_byte)[1] = 134567; // OK
((IDirectIndex<int, byte>)int_byte)[134567] = 41; // OK
var int_int = new DoubleIndexer<int, int>();
((IInvertedIndex<int, int>)int_int)[1] = 1345; // OK
((IDirectIndex<int, int>)int_int)[13] = 5431; // OK
第一版
public interface IIndex<T1, T2>
{
T2 this[T1 key] { get; set; }
}
internal class DoubleIndexer<T1, T2> : IIndex<T1, T2>
{
public T1 this[T2 key]
{
get => default;
set { Console.WriteLine($"T1 this[T2 key]: {value}"); }
}
T2 IIndex<T1, T2>.this[T1 key]
{
get => default;
set { Console.WriteLine($"T2 IIndex<T1, T2>.this[T1 key]: {value}"); }
}
}
测试示例:
var int_string = new DoubleIndexer<int, string>();
((IIndex<int, string>)int_string)[1] = "Hello"; // OK
int_string["Hello"] = 1; // OK
var int_byte = new DoubleIndexer<int, byte>();
int_byte[1] = 134567; // OK
((IIndex<int, byte>)int_byte)[134567] = 41; // OK
var int_int = new DoubleIndexer<int, int>();
int_int[1] = 1345; // OK
((IIndex<int, int>)int_int)[13] = 5431; // OK
仅在避免以下情况时才需要全限定名称: 类使用相同的索引器实现多个接口 签名