我在C#中实现了一种联网的多类型哈希表,我遇到了一些问题。每个条目都有一些与之关联的元数据,如字符串名称和ID号。我的代码中有些地方我正在操作条目,但我不一定需要知道它们包含的类型。因此,例如,在解析更新数据包时,我希望能够做到这样的事情:
entry.Name = ParseName(data);
entry.Id = ParseId(data);
entry = ParseValue(entry, data);
table.Insert(entry);
其中ParseValue()
获取条目,根据我从网络获得的数据设置某种“值”参数和某种“类型”参数,并返回通用条目。然后,当我想对数据执行某些操作时,我希望能够执行切换entry.Type
之类的操作,然后通过将其转换为entry.Type
来使用该值。但每次我尝试做这样的事情时,我最终都需要将类型参数放在我不知道类型的地方。我知道该类型是6种可能类型之一(bool
,double
,string
,List<bool>
,List<double>
或List<string>
),但我不知道它是哪种类型。有没有办法在C#中做到这一点,甚至更好,有没有办法改变我的设计,这不是问题?
注意:上面的所有代码都是对我正在做的事情的简化表示,因为我不想进入解密这些数据包时需要做的麻烦的事情。
编辑:我可能尝试使用它的一个示例(我知道这不是有效的C#)
foreach( entry in table ) {
switch( entry.Type ) {
case typeof(bool):
displayBool( (bool)(entry.Value) );
break;
case typeof(double):
displayDouble( (double)(entry.Value) );
break;
case typeof(string):
displayString( (string)(entry.Value) );
break;
case typeof(List<bool>):
displayListOfBool( (List<bool>)(entry.Value) );
break;
case typeof(List<double>):
displayListOfDouble( (List<double>)(entry.Value) );
break;
case typeof(List<string>):
displayListOfStrings( (List<string>)(entry.Value) );
break;
}
}
编辑2:如果有帮助,我正在尝试实施的规范就在这里:http://firstforge.wpi.edu/sf/docman/do/downloadDocument/projects.wpilib/docman.root/doc1318
答案 0 :(得分:3)
每次看到类似
的内容 switch( entry.Type )
是时候考虑多态性了。
假设(为了简单起见)您希望执行类似
的操作switch( entry.Type )
{
case typeof(bool):
displayBool( (bool)(entry.Value) );
break;
case typeof(double):
displayDouble( (double)(entry.Value) );
break;
}
我认为编写
会更清晰entry.Display();
通过继承和多态来完成这项工作。然后你将拥有一个通用的基本抽象类和其他实现不同Display()的类 - 一个用于你正在使用的每个实际类型。
abstract class BaseEntry<T>
{
public T Value {get; set;}
public string Name {get; set;}
public abstract void Display();
}
class BoolEntry : BaseEntry<bool>
{
public override void Display()
{
// Your code here
}
}
如果Display()不是Entry应该做的事情,你可以给它一个引用其他对象的东西。
答案 1 :(得分:1)
我喜欢Vadim的方法。你可以这样为你工作:
abstract class BaseEntry
{
public abstract object Value { get; }
public string Name { get; set; }
public abstract void Display();
public abstract void SetValue(object value);
}
你可以像这样实现它:
class BoolEntry : BaseEntry
{
public bool ConcreteValue { get; protected set; }
public override object Value
{
get
{
return this.ConcreteValue;
}
}
public override void SetValue(object value)
{
this.ConcreteValue = (bool)value;
}
public void SetValue(bool value)
{
this.ConcreteValue = value;
}
public override void Display()
{
Console.WriteLine("Here is your bool: " + this.ConcreteValue.ToString());
}
}
而不是在Entry类中实现类型约束您可以构建仅允许给定类型的值的哈希表。这是一个例子:
class ConstraintHashTable<TKey, TValue> // Implement all the good interfaces
{
private HashSet<Type> AllowedTypes;
private Dictionary<TKey, TValue> Dictionary;
public TValue this[TKey key]
{
get
{
return this.Dictionary[key];
}
}
public ConstraintHashTable(HashSet<Type> allowedTypes)
{
this.AllowedTypes =
allowedTypes == null ? new HashSet<Type>() : allowedTypes;
this.Dictionary = new Dictionary<TKey, TValue>();
}
public void Add(TKey key, TValue value)
{
if (this.AllowedTypes.Contains(value.GetType()) == false)
{
throw new ArgumentException(
"I don't accept values of type: " + value.GetType().FullName + ".");
}
this.Dictionary.Add(key, value);
}
}
然后你可以创建一个只接受BoolEntry值的哈希表,但是将它保存为BaseEntry,如下所示:
var allowedTypes = new HashSet<Type>(new Type[] { typeof(BoolEntry) });
var cht = new ConstraintHashTable<string, BaseEntry>(allowedTypes);
cht.Add("001", new BoolEntry());
cht["001"].SetValue(true);
cht["001"].Display();
cht["001"].SetValue(false);
cht["001"].Display();