0

我正在用 C# 实现一种联网的多类型哈希表,但遇到了一些问题。每个条目都有一些与之关联的元数据,例如字符串名称和 ID 号。我的代码中有一些地方是我对条目进行操作的地方,但我不一定需要知道它们包含的类型。因此,例如,在解析更新数据包时,我希望能够执行以下操作:

entry.Name = ParseName(data);
entry.Id = ParseId(data);
entry = ParseValue(entry, data);
table.Insert(entry);

whereParseValue()获取条目,根据我从网络获得的数据设置某种“值”参数和某种“类型”参数,然后返回一个通用条目。然后,当我想对数据做一些事情时,我希望能够做一些事情,比如切换entry.Type,然后通过将其转换为entry.Type. 但是每次我尝试做这样的事情时,我最终都需要将类型参数放在我不知道类型的地方。我知道该类型是 6 种可能的类型之一(booldoublestringList<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

4

2 回答 2

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 应该做的事情,你可以给它一个对其他能够做这种事情的对象的引用。

于 2013-09-08T18:35:30.270 回答
1

我喜欢瓦迪姆的方法。你可以这样为你工作:

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();
于 2013-09-08T20:11:45.470 回答