我有一个类的层次结构:
public class Key
{
private readonly string _name;
public Key(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
public override bool Equals(object obj)
{
if (obj == null) return false;
if (GetType() != obj.GetType()) return false;
Key other = (Key)obj;
return Name == other.Name;
}
public override int GetHashCode()
{
return GetType().GetHashCode() ^ _name.GetHashCode();
}
public override string ToString()
{
return GetType() + "(" + Name + ")";
}
}
不同的键:
public class CarKey : Key
{
public CarKey(string name)
: base(name)
{
}
}
public class VanKey : CarKey
{
public VanKey(string name)
: base(name)
{
}
}
public class CoupeKey : CarKey
{
public CoupeKey(string name)
: base(name)
{
}
}
我有一本字典IDictionary<Key, Data>
。我想实现一种方法来查找字典中最相关的数据:
IDictionary<Key, Data> dict;
public Data MostRelevantData(Key key)
{
if(dict.Contains(key)) return dict[key];
//try base class of key (with the same name) recursively
throw new KeyNotFound();
}
是否可以在没有反思的情况下实施MostRelevantData
?如果它更容易,可以重新设计Key
类。
编辑:示例:
dict[new Key("A")] = "Data A";
dict[new CarKey("B")] = "Data B";
dict[new CoupeKey("B")] = "Data B1";
dict[new CoupeKey("C")] = "Data C";
MostRelevantData(new CoupeKey("B"));//returns "Data B1"
MostRelevantData(new CoupeKey("A"));//returns "Data A"
MostRelevantData(new CoupeKey("C"));//returns "Data C"
MostRelevantData(new CarKey("C"));//throws
MostRelevantData(new CarKey("B"));//returns "Data B"
MostRelevantData(new VanKey("C"));//throws
MostRelevantData(new VanKey("B"));//returns "Data B"
答案 0 :(得分:3)
您可以向Key
添加方法以获取基本密钥实例:
public class Key
{
public virtual Key GetBaseKey()
{ return null; }
}
public class CarKey : Key
{
public override Key GetBaseKey()
{ return new Key(this.Name); }
}
然后您的搜索可以写成:
public Data MostRelevantData(Key key)
{
while(key != null)
{
if(dict.Contains(key)) return dict[key];
key = key.GetBaseKey();
}
throw new KeyNotFound();
}
缺点是你必须有效地复制每个子类中的密钥层次结构。
答案 1 :(得分:0)
在没有反思的情况下实施MostRelevantData
非常容易。这是一个扩展方法:
public static class DictionaryExtensionMethods
{
public static T MostRelevantData<T>(this IDictionary<Key, T> dict, Key key)
{
if (dict.ContainsKey(key))
{
return dict[key];
}
Key relevantKey = dict.Keys.FirstOrDefault(
loop => key.IsRelevant(loop));
if (relevantKey != null)
{
return dict[relevantKey];
}
throw new KeyNotFoundException();
}
}
但是,显然,您需要实现Key.IsRelevant
才能实现此功能。幸运的是,这也是非常直接的,由Type.IsSubclassOf方法提供:
public class Key
{
public bool IsRelevant(Key other)
{
return (this.GetType().IsSubclassOf(other.GetType()))
&& (this.Name == other.Name);
}
}
通过上面的实现,以下Visual Studio单元测试所有传递:
public class PolymorphicKeysTests
{
public PolymorphicKeysTests()
{
}
private Dictionary<Key, string> dict;
[TestInitialize]
public void TestInitialize()
{
dict = new Dictionary<Key, string>();
dict[new Key("A")] = "Data A";
dict[new CarKey("B")] = "Data B";
dict[new CoupeKey("B")] = "Data B1";
dict[new CoupeKey("C")] = "Data C";
}
[TestMethod]
public void CoupeKeyB()
{
Assert.AreEqual("Data B1", dict.MostRelevantData(new CoupeKey("B")));
}
[TestMethod]
public void CoupeKeyA()
{
Assert.AreEqual("Data A", dict.MostRelevantData(new CoupeKey("A")));
}
[TestMethod]
public void CoupeKeyC()
{
Assert.AreEqual("Data C", dict.MostRelevantData(new CoupeKey("C")));
}
[TestMethod]
[ExpectedException(typeof(KeyNotFoundException))]
public void CarKeyC()
{
dict.MostRelevantData(new CarKey("C"));
}
[TestMethod]
public void CarKeyB()
{
Assert.AreEqual("Data B", dict.MostRelevantData(new CarKey("B")));
}
[TestMethod]
[ExpectedException(typeof(KeyNotFoundException))]
public void VanKeyC()
{
dict.MostRelevantData(new VanKey("C"));
}
[TestMethod]
public void VanKeyB()
{
Assert.AreEqual("Data B", dict.MostRelevantData(new VanKey("B")));
}
}