2) Создайте такой метод, как {{X0}}, который инициализирует хранилище учетных записей, но в вашем тесте имитируйте этот метод:

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
Grzenio 21 Мар 2014 в 18:32
Что ты пытаешься сделать? Получить значение на основе его Type? Можете ли вы привести пример, как вы хотите использовать этот код?
 – 
Arcturus
21 Мар 2014 в 18:36
Можете ли вы описать, чего вы пытаетесь достичь?
 – 
Sergey Berezovskiy
21 Мар 2014 в 18:36
Похоже, если экземпляр CoupeKey с Name "ASDF" не найден, Grzenio хотел бы, чтобы он увидел, есть ли какие-либо другие объекты CarKey с Name "ASDF" (то есть он может вернуть VanKey, который имеет тот же "ASDF" Name). (Не уверен, как бы вы определили, является ли VanKey более релевантным, чем, скажем, SedanKey, хотя, если бы оба имели совпадающее Name)
 – 
Chris Sinclair
21 Мар 2014 в 18:39
@Grzenio: я бы предложил иметь две таблицы поиска по словарю. Один Dictionary<Key, Data> dict, а другой Dictionary<string, List<Key>> NameLookup. Всякий раз, когда вы добавляете Key, вы сохраняете запись в NameLookup. Когда ключи добавляются с соответствующими именами, они будут заполнять соответствующие списки List<Key>. Когда вы выполняете поиск, если Key не существует в dict, вы можете выполнить вторую проверку в NameLookup; если там есть дополнительные совпадения Keys, вы можете вытащить их соответствующие Data из dict.
 – 
Chris Sinclair
21 Мар 2014 в 18:44
@SergeyBerezovskiy, добавил примеры
 – 
Grzenio
21 Мар 2014 в 18:55

2 ответа

Лучший ответ

Вы можете добавить метод к Key для получения экземпляра базового ключа:

public class Key
{
    public virtual Key GetBaseKey()
    { return null; }
}

public class CarKey : Key
{
    public override Key GetBaseKey()
    { return new Key(this.Name); }
}

Возможно более быстрое решение, чем AjV

public Data MostRelevantData(Key key)
{
  while(key != null)
  {
    if(dict.Contains(key)) return dict[key];
    key = key.GetBaseKey();
  }
  throw new KeyNotFound();
}

Обратной стороной является то, что вам придется эффективно дублировать ключевую иерархию в каждом подклассе.

3
Lee 21 Мар 2014 в 18:51
Вы можете использовать отражение для реализации GetBaseKey как невиртуального метода в Key.
 – 
Servy
21 Мар 2014 в 18:56
- Да, вы могли бы, ОП, кажется, хочет избежать размышлений.
 – 
Lee
21 Мар 2014 в 18:57

В myClass methodToTest выглядит так:

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);
    }
}

Я новичок в OCMockObjects и пытаюсь имитировать метод экземпляра класса ACAccount:

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")));
    }
}
0
Edmund Schweppe 21 Мар 2014 в 22:39