Здравствуйте. Не так давно выполнил (во всяком случае так считал) тестовое задание. Описание задачи: Спроектируйте и реализуйте класс-коллекцию для хранения элементов, имеющих уникальный составной ключ [Id, Name] (Id и Name – компоненты ключа, могу быть произвольного типа). Вы можете использовать любую встроенную коллекцию .NET Framework.
Предоставьте необходимые с вашей точки зрения методы для этой коллекции, а так же методы для эффективного по скорости получения элементов по их Id ИЛИ Name.
Программа должна содержать пример использования коллекции с идентификатором ключа в виде пользовательского типа (т.е. Id в ключе – UserType, объекты UserType должны сравниваться по значению).
Дополнительно: Создайте потокобезопасную реализацию этой коллекции (не использовать коллекции из пространства имён System.Collections.Concurrent).
То, что я предложил в качестве решения:
Элемент и UserType:
/// <summary>
/// Элемент коллекции
/// </summary>public class MyElement
{
private UserType id;
private String name;
public String Name
{
get { return name; }
set { name = value; }
}
public UserType Id
{
get { return id; }
set { id = value; }
}
public override int GetHashCode()
{
return Name.GetHashCode() ^ Id.GetHashCode();
}
public override bool Equals(object obj)
{
if (!(obj is MyElement))
{
MyElement el = (MyElement)obj;
return Id == el.Id && Name == el.Name;
}
else
{
return false;
}
}
public override string ToString()
{
return String.Format("Id:{0}, Name:{1}",id.Content.ToString(), Name);
}
}
/// <summary>
/// Тип для поля Id
/// </summary>public struct UserType
{
private int content;
public int Content
{
get { return content; }
set { content = value; }
}
public override int GetHashCode()
{
return Content^Content;
}
public override bool Equals(object obj)
{
if (!(obj is UserType))
{
UserType ut = (UserType)obj;
return Content == ut.Content;
}
else
{
return false;
}
}
public static Boolean operator == (UserType ut1, UserType ut2)
{
return ut1.Content == ut2.Content;
}
public static Boolean operator != (UserType ut1, UserType ut2)
{
return ut1.Content != ut2.Content;
}
public override string ToString()
{
return Content.ToString();
}
}
Индекс:
/// <summary>
/// Индекс для коллекции
/// </summary>public struct MyId : IEquatable<MyId>
{
private readonly UserType id;
private readonly String name;
public UserType Id
{
get
{
return id;
}
}
public String Name
{
get
{
return name;
}
}
//public MyId(UserType _id, String _name)
//{
// id = _id;
// name = _name;
//}public MyId(MyElement element)
{
id = element.Id;
name = element.Name;
}
public override int GetHashCode()
{
return id.GetHashCode() ^ name.GetHashCode();
}
public bool Equals(MyId other)
{
if ((object)other == null)
{
return false;
}
else
{
return id == other.id && name == other.name;
}
}
public override bool Equals(object obj)
{
return Equals((MyId)obj);
}
public static Boolean operator == (MyId u1, MyId u2)
{
return (u1.id == u2.id) && (u1.name == u2.name);
}
public static Boolean operator != (MyId u1, MyId u2)
{
return (u1.id == u2.id) || (u1.name == u2.name);
}
public override string ToString()
{
return String.Format("Key(id={0}, name={1})", id.ToString(), name);
}
}
Собственно, коллекция:
/// <summary>
/// Класс-коллекция. Потокобезопасность реализована для метода Add.
/// Т.к. коллекция наследует от Dictionary, она поддерживает необходимые базовые методы
/// </summary>
/// <typeparam name="TKey">В качестве ключа используется MyId</typeparam>
/// <typeparam name="TValue">Элемент коллекции</typeparam>public class MyCollection<TKey, TValue> : Dictionary<MyId, TValue>
{
private readonly object syncRoot = new object();
private Dictionary<MyId, TValue> _myCollection = new Dictionary<MyId, TValue>();
/// <summary>
/// Перекрываем метод вставки в коллекцию для реализации потокобезопасности.
/// Примечание: при попытка вставить элемент с повторяющимся индексом просто игнорируем вставку.
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>public new void Add(MyId key, TValue value)
{
lock (syncRoot)
{
if (!this.ContainsKey(key))
{
base.Add(key, value);
}
}
}
#region Реализация методов поиска указанных в задании
public MyElement GetElementById(UserType _id)
{
dynamic result;
lock (syncRoot)
{
result = this.Where(x => x.Key.Id == _id).SingleOrDefault().Value;
}
if (result is MyElement)
{
return result as MyElement;
}
else
{
return null;
}
}
public MyElement GetElementByName(String _name)
{
dynamic result;
lock (syncRoot)
{
result = this.Where(x => x.Key.Name == _name).SingleOrDefault().Value;
}
if (result is MyElement)
{
return result as MyElement;
}
else
{
return null;
}
}
public MyElement GetElementByIdOrName(object o)
{
if (o is String)
{
return GetElementByName((string)o);
}
else if (o is UserType)
{
return GetElementById((UserType)o);
}
else
{
return null;
}
}
#endregion
}
Этот вариант решения, как видно, не понравился проверявшему.
Буду признателен, если "ткнете носом" в ошибки. Понимаю, что, возможно подошел к решению довольно формально, но по требованиям вроде все реализовал. Или чего-то не так понял.
12/5/2013 6:32 PM, mig84 пишет:
> Этот вариант решения, как видно, не понравился проверявшему. > Буду признателен, если "ткнете носом" в ошибки. Понимаю, что, возможно > подошел к решению довольно формально, но по требованиям вроде все > реализовал. Или чего-то не так понял.
Сколько раз уже здесь срачи на эту тему были. Возможно нафиг им никто не
нужен, возможно кто-то сильно меньше тебя попросил, возможно знакомый
пришел и т.д.
З.Ы. Для тебе это сложно было? Ты много времени потратил? Тебе так важно
устроиться в гадюшник, где даже не соизволили тебе высказать свое мнение
о том, что ты написал? Потому, как это хамство дать человеку делать
тестовое задание и не отвечать и в работе там 100% такой же хамский
подход принят.
Для быстрого поиска под id или name лучше бы иметь две хэш-таблицы. Вообще непонятно причем тут составной ключ, если получать данные предпологается только по отдельным частям ключа.
V>З.Ы. Для тебе это сложно было? Ты много времени потратил? Тебе так важно V>устроиться в гадюшник, где даже не соизволили тебе высказать свое мнение V>о том, что ты написал? Потому, как это хамство дать человеку делать V>тестовое задание и не отвечать и в работе там 100% такой же хамский V>подход принят.
Да, собственно я все это понимаю.
Времени потратил на это совсем немного, но просто любопытны соображения проверяющих.
Здравствуйте, mig84, Вы писали:
Х>>UserType.getHashCode() будет всегда давать 0. Ты число само с собой суммируешь.
M>+1 действительно пропустил. Спасибо. M>Модифицируем до:
Здравствуйте, mig84, Вы писали:
M>Здравствуйте. Не так давно выполнил (во всяком случае так считал) тестовое задание. Описание задачи: M>Этот вариант решения, как видно, не понравился проверявшему. M>Буду признателен, если "ткнете носом" в ошибки. Понимаю, что, возможно подошел к решению довольно формально, но по требованиям вроде все реализовал. Или чего-то не так понял.
Был бы я проверяющим — тоже бы не понравилось. Слишком сложно сделано, много ляпов, да и задание не выполнено. Код джуниора.
1. Id и Name – компоненты ключа, могу быть произвольного типа — этого нет. У вас Id и Name типа string
2. public new void Add(MyId key, TValue value) — зачем вам new? так следует делать только в экстренных случаях
3. lock вообще используется в случайных местах и неоптимально
4. Вот это вообще жесть какая-то.
if (result is MyElement)
{
return result as MyElement;
}
else
{
return null;
}
M>1. Id и Name – компоненты ключа, могу быть произвольного типа — этого нет. У вас Id и Name типа string M>2. public new void Add(MyId key, TValue value) — зачем вам new? так следует делать только в экстренных случаях M>3. lock вообще используется в случайных местах и неоптимально M>4. Вот это вообще жесть какая-то. M>
M> if (result is MyElement)
M> {
M> return result as MyElement;
M> }
M> else
M> {
M> return null;
M> }
M>
Спасибо за комментарий!
1. "Произвольного типа" можно трактовать по разному. Скорее всего тут Вы правы, действительно имелось ввиду generic.
2. Каким образом иначе можно реализовать потокобезопасность при вставке? Можно было бы обойтись Concurent коллекцией, но по заданию — нельзя.
3. lock оправдан в методе Add (на мой взгляд). В GetElementById — лишний.
4. Да, не оптимально. Можно было одной строкой обойтись.
Здравствуйте, mig84, Вы писали:
M>Спасибо за комментарий! M>1. "Произвольного типа" можно трактовать по разному. Скорее всего тут Вы правы, действительно имелось ввиду generic.
Имелось в виду generic. M>4. Да, не оптимально. Можно было одной строкой обойтись.
Дело не в строках, дело в подходе.
От вас наверняка ждали что-то вроде
class KeyValueHolder<TId, TName, T>
{
private int _count;
private readonly Dictionary<TId, Dictionary<TName, T>> _dicById;
private readonly Dictionary<TName, Dictionary<TId, T>> _dicByName;
public KeyValueHolder()
{
_dicById = new Dictionary<TId, Dictionary<TName, T>>();
_dicByName = new Dictionary<TName, Dictionary<TId, T>>();
}
/// <summary>
/// Получить элементы, имеющие заданный Id
/// </summary>public IList<T> GetById(TId id)
{
Dictionary<TName, T> dicName;
if (!_dicById.TryGetValue(id, out dicName)) return new List<T>();
return dicName.Values.ToList();
}
/// <summary>
/// Получить элементы, имеющие заданный Name
/// </summary>public IList<T> GetByName(TName name)
{
Dictionary<TId, T> dicId;
if (!_dicByName.TryGetValue(name, out dicId)) return new List<T>();
return dicId.Values.ToList();
}
/// <summary>
/// Получить элемент по ключу
/// </summary>public T Get(TId id, TName name)
{
Dictionary<TName, T> dicName;
if (!_dicById.TryGetValue(id, out dicName)) return default(T);
T value;
if (dicName.TryGetValue(name, out value)) return value;
return default(T);
}
/// <summary>
/// Добавить элемент
/// </summary>public void Add(TId id, TName name, T value)
{
Dictionary<TName, T> dicName;
if (!_dicById.TryGetValue(id, out dicName))
{
dicName = new Dictionary<TName, T>();
_dicById.Add(id, dicName);
}
if (dicName.ContainsKey(name))
{
throw new ArgumentOutOfRangeException("name", "Element with given (Id,Name) already exists");
}
Dictionary<TId, T> dicId;
if (!_dicByName.TryGetValue(name, out dicId))
{
dicId = new Dictionary<TId, T>();
_dicByName.Add(name, dicId);
}
if (dicId.ContainsKey(id))
{
throw new ArgumentOutOfRangeException("name", "Element with given (Id,Name) already exists");
}
dicId.Add(id, value);
dicName.Add(name, value);
_count++;
}
/// <summary>
/// Удалить элемент
/// </summary>public void Remove(TId id, TName name)
{
Dictionary<TName, T> dicName;
if (!_dicById.TryGetValue(id, out dicName)) return;
Dictionary<TId, T> dicId;
if (!_dicByName.TryGetValue(name, out dicId)) return;
dicId.Remove(id);
dicName.Remove(name);
_count--;
}
public int Count
{
get
{
return _count;
}
}
}
class Program
{
static void Main(string[] args)
{
var holder = new KeyValueHolder<int, string, string>();
holder.Add(5, "Петя", "Значение0");
holder.Add(5, "Вася", "Значение1");
holder.Add(6, "Вася", "Значение2");
holder.Add(7, "Вася", "Значение3");
Debug.Assert(holder.Count == 4);
var elementsByName = holder.GetByName("Вася");
var elementsById = holder.GetById(5);
holder.Remove(7, "Вася");
Debug.Assert(holder.Count == 3);
}
}
Довести до потокобезопасности предлагаю в качестве домашнего задания.
12/5/2013 7:12 PM, mig84 пишет:
> Времени потратил на это совсем немного, но просто любопытны соображения > проверяющих.
Если Хэлкар не тот проверяющий, то соображения у них могут быть любыми.
Но, то что тебе не ответили — это хамство. А хамы обычно всегда хамы.
Здравствуйте, Хэлкар, Вы писали:
Р>>Ты не понял что такое составной ключ и на кой черт он нужен.
Х>Я тоже по заданию не понял на кой черт здесь нужен составной ключ.
Здравствуйте, Хэлкар, Вы писали:
Х>>Я тоже по заданию не понял на кой черт здесь нужен составной ключ. Х>Можете объяснить?
Спроектируйте и реализуйте класс-коллекцию для хранения элементов, имеющих уникальный составной ключ [Id, Name] (Id и Name – компоненты ключа, могу быть произвольного типа).
Получаем в сишной терминологии
template <typename A, typename B, typename C>
class our_magic_container_t: private std::map<std::pair<A, B>, C>
{
};
а так же методы для эффективного по скорости получения элементов по их Id ИЛИ Name.
Получаем два метода
template <class Iterator>
void our_magic_container::copy_into(const A & id, Iterator pos);
template <class Iterator>
void our_magic_container::copy_into(const B & name, Iterator pos);
Здравствуйте, mig84, Вы писали:
M>Предоставьте необходимые с вашей точки зрения методы для этой коллекции, а так же методы для эффективного по скорости получения элементов по их Id ИЛИ Name.
... M>Этот вариант решения, как видно, не понравился проверявшему. M>Буду признателен, если "ткнете носом" в ошибки. Понимаю, что, возможно подошел к решению довольно формально, но по требованиям вроде все реализовал. Или чего-то не так понял.
Я не очень силен в C# и возможно чего и не понял в коде, но мне показалось что выделенная часть условия не была реализована.
Для уточнения задам простой вопрос.
Допустим я добавил в Вашу коллекцию миллион элементов.
Какое максимальное количество итераций потребуется для поиска элемента по Id и какое по Name?
Собственно в дотнете мы получаем ровно тоже самое. Вопрос — зачем нужен "составной ключ", если мы всегда запрашиваем данные по одному или по другому параметру?
Здравствуйте, Хэлкар, Вы писали:
Х>Собственно в дотнете мы получаем ровно тоже самое. Вопрос — зачем нужен "составной ключ", если мы всегда запрашиваем данные по одному или по другому параметру?
По составному ключу мы получаем не больше одного значения. По его части мы получаем произвольное число значений. Т. е. вот это
public MyElement GetElementById(UserType _id)
должно быть заменено на
public IEnumerable<MyElement> GetElementById(UserType _id)
познания в C# не позволяет мне указать произвольный контейнер, куда будут вставлены элементы типа MyElement.
Здравствуйте, mig84, Вы писали:
M>Здравствуйте. Не так давно выполнил (во всяком случае так считал) тестовое задание. Описание задачи: M>Спроектируйте и реализуйте класс-коллекцию для хранения элементов, имеющих уникальный составной ключ [Id, Name] (Id и Name – компоненты ключа, могу быть произвольного типа). Вы можете использовать любую встроенную коллекцию .NET Framework. M>Предоставьте необходимые с вашей точки зрения методы для этой коллекции, а так же методы для эффективного по скорости получения элементов по их Id ИЛИ Name. M>Программа должна содержать пример использования коллекции с идентификатором ключа в виде пользовательского типа (т.е. Id в ключе – UserType, объекты UserType должны сравниваться по значению). M>Дополнительно: Создайте потокобезопасную реализацию этой коллекции (не использовать коллекции из пространства имён System.Collections.Concurrent). M>
2ГИС детектед . Тут generic конечно был нужен.
Могу показать код для этой задачи который они приняли
Здравствуйте, mig84, Вы писали:
Х>>Охм, посмотрел GetElementById и GetElementByName — зачем там dynamic???
M>А почему бы и нет? ))) Просто поменять на MyElement забыл.
Там ретурна ещё нет. Можно добавить ещё myFavouritVar, которую не инициализировать, но от этого код станет только хуже.
public override bool Equals(object obj)
{
if (!(obj is MyElement))
{
MyElement el = (MyElement)obj;
return Id == el.Id && Name == el.Name;
}
else
{
return false;
}
}
Может я совсем C# уже забыл, но что вернёт obj is MyElement если obj имеет тип MyElement?
mig84, ты код запускал хоть раз?
Здравствуйте, alzt, Вы писали:
A>Скорее всего нужен был ещё метод, который ищет по MyId.
А еще возможен вариант проверки коммуникативных навыков, задание в общем-то составлено витиевато, посему вполне могли проверять, насколько соискатель будет уточнять задание.
Здравствуйте, Mystic, Вы писали:
A>>Скорее всего нужен был ещё метод, который ищет по MyId.
M>А еще возможен вариант проверки коммуникативных навыков, задание в общем-то составлено витиевато, посему вполне могли проверять, насколько соискатель будет уточнять задание.
Это вряд ли. Людям ответить лень, а уж что-то уточнять и тем более.
В качестве правила хорошего тона (собственно и кода), предостваили
бы за одно и юнит-тесты для Вашего кода. Уже был бы неплохой плюс к карме.
Да и сами тесты помогли бы Вам лучше понять код и требования.
12/6/2013 2:39 PM, Sharov пишет:
> В качестве правила хорошего тона (собственно и кода), предостваили > бы за одно и юнит-тесты для Вашего кода. Уже был бы неплохой плюс к карме. > Да и сами тесты помогли бы Вам лучше понять код и требования.
Так это ты задачку давал? А что ж человеку не ответил, а отвечаешь
только здесь?
Здравствуйте, Vzhyk, Вы писали:
V>И где там про юнит-тесты?
А нигде, но вообще говоря было очень грамотно их предоставить.
Т.е. сразу видно, что человек подошел к задаче грамотно, капитально.
Представьте ситуацию: нужно выбрать из двух претендентов, которые с правились с
задачей на ура, т.е. код удовлетворяет всем условиям, но у одно есть юнит-тесты, а
у другого нет. И тут можно склонить чашу весов в свою пользу.
Я не фанат юнит-тестов, сам их редко пишу (считай не пишу вовсе),
но для собеседования уж постарался бы.
12/6/2013 3:21 PM, Sharov пишет:
> Т.е. сразу видно, что человек подошел к задаче грамотно, капитально. > Представьте ситуацию: нужно выбрать из двух претендентов, которые с > правились с > задачей на ура, т.е. код удовлетворяет всем условиям, но у одно есть > юнит-тесты, а > у другого нет. И тут можно склонить чашу весов в свою пользу.
А еще может быть куча нюансов, почему один подошел, а другой нет. Другой
мог быть банально грамотнее, банально дешевле и т.д. и всякие UT могли
не иметь никакого отношения. А вообще можно сказать и так, человек
зачем-то начал делать то, что не просили, нафига, нужен ли нам такой
"инициативный".
Из обсуждения здесь уже видно, что ТС не очень крутой программист на
фоне некоторых местных (я в С# ничего не знаю и посему доверяю местным
знающим) и вполне возможно, что он не подошел по квалификации. Но, это
простейшая культура и на минимальном уровне, если человек сделал задание
и прислал, ответить ему, даже стандартной фразой (по крайней мере я так
понял пост ТС).
З.Ы. А вообще, насчет тестовых заданий. Я их противник, кроме случая,
давать их выпускнику вуза, если у того нет опыта работы на програмерской
конторе.
З.З.Ы. Помню, сделал одним тестовое задание, прошел, конечно и даже 2
месяца поработал и сделал ноги оттуда. С таким говенным кодом и
настолько же убогой организацией разработки мне не приходилось ни до ни
после работать. Ну и еще обычно самые говенные конторы тестовые задания
просят, но этим говоришь досвидания сразу же. Одни вообще ругаться по
телефону стали (да, встречаются и такие), когда я сказал, что мне
выполнять их тестовое задание не интересно.
Здравствуйте, Vzhyk, Вы писали:
V>Но, это V>простейшая культура и на минимальном уровне, если человек сделал задание V>и прислал, ответить ему, даже стандартной фразой (по крайней мере я так V>понял пост ТС).
ТС и ответили, мол не то. Ну не построчно же с ним разбирать код. Банально
может быть некогда. Если ТС грамотный человек, то он придет на форум программистов,
покажет задачу, свое решение, и ему укажут на косяки. И это кстати, будет
лучше, т.к. больше народу посмотрит на код.
V>З.Ы. А вообще, насчет тестовых заданий. Я их противник, кроме случая, V>давать их выпускнику вуза, если у того нет опыта работы на програмерской V>конторе.
S>Да и сами тесты помогли бы Вам лучше понять код и требования.
Поддерживаю, я бы еще написал сравнительные нагрузочные тесты.
Без тестов самому не понятно, делает ли оно то, что ожидается.
Уж если взялся, то писать как для себя.
Хотя, сам бы стал делать задание, только если бы очень хотелось именно в эту кантору.
Здравствуйте, Vzhyk, Вы писали:
>> ТС привел описание задачи, Ваш КО. V>И где там про юнит-тесты?
Ну про юнит тесты действительно явно сказано не было.
Но вот эта строчка
M>Программа должна содержать пример использования коллекции с идентификатором ключа в виде пользовательского типа (т.е. Id в ключе – UserType, объекты UserType должны сравниваться по значению).
однозначно содержит требование написать не только коллекцию, но и код ее использующий.
А уже UT это будет или main совсем не важно.
И именно в этом коде должен появиться UserType как параметр(может в # используется другой термин но смысл я думаю понятен) обобщенной коллекции.
А у ТС UserType — это тип поля в MyId, а MyId используется внутри коллекции.
В общем все это больше похоже на фэйк или загадку типа "кто найдет больше несоответствий условиям задачи"
Большое спасибо всем за уделенное этой задаче время.
Действительно куча ошибок. Наверное и правда, дело в том, что после тяжелого рабочего дня и недели в целом.
По сути главная проблема — неверная трактовка задания как такого, ну и отсутствие code review за самим собой, так как делал достаточно быстро.
Отдельное спасибо Хэлкар,Vzhyk,mogikanin,Ромашка.
Кстати, в sln был включен проект с UT. Понятно, что так как условие задачи было воспринято мной неверно, то и тесты некорректны.
В общем, еще раз всем спасибо.
На этом тему можно считать закрытой.
/// <summary>
/// Проверяем возможность заполнить коллекцию
/// </summary>
[TestMethod]
public void TestMethod1()
{
#region Fake
MyCollection<MyId, MyElement> collection = new MyCollection<MyId, MyElement>();
for (int i = 1; i < 10; i++)
{
MyElement el = new MyElement()
{
Id = new UserType() { Content = i },
Name = String.Format("Unit - {0}", i)
};
MyId mid = new MyId(el);
collection.Add(mid, el);
}
#endregion
Assert.AreEqual(9, collection.Count);
}
/// <summary>
/// Проверяем реакцию на вставку дубликата
/// </summary>
[TestMethod]
public void TestMethod2()
{
#region Fake
MyCollection<MyId, MyElement> collection = new MyCollection<MyId, MyElement>();
for (int i = 1; i < 10; i++)
{
MyElement el = new MyElement()
{
Id = new UserType() { Content = i },
Name = String.Format("Unit - {0}", i)
};
MyId mid = new MyId(el);
collection.Add(mid, el);
}
#endregion
MyElement newElement = new MyElement()
{
Id = new UserType() { Content = 1 },
Name = String.Format("Unit - {0}", 1 )
};
int initCount = collection.Count;
collection.Add(new MyId(newElement), newElement);
Assert.AreEqual(initCount, collection.Count);
}
/// <summary>
/// Проверяем работает ли поиск по Id
/// </summary>
[TestMethod]
public void TestMethod3()
{
#region Fake
MyCollection<MyId, MyElement> collection = new MyCollection<MyId, MyElement>();
for (int i = 1; i < 10; i++)
{
MyElement el = new MyElement()
{
Id = new UserType() { Content = i },
Name = String.Format("Unit - {0}", i)
};
MyId mid = new MyId(el);
collection.Add(mid, el);
}
#endregion
MyElement lostAndFound = collection.GetElementById(new UserType() { Content=5 });
Assert.AreNotEqual(null, lostAndFound);
}
/// <summary>
/// Проверяем работает ли поиск по Name
/// </summary>
[TestMethod]
public void TestMethod4()
{
#region Fake
MyCollection<MyId, MyElement> collection = new MyCollection<MyId, MyElement>();
for (int i = 1; i < 10; i++)
{
MyElement el = new MyElement()
{
Id = new UserType() { Content = i },
Name = String.Format("Unit - {0}", i)
};
MyId mid = new MyId(el);
collection.Add(mid, el);
}
#endregion
MyElement lostAndFound = collection.GetElementByName("Unit - 7");
Assert.AreNotEqual(null, lostAndFound);
}
/// <summary>
/// Проверяем работает ли поиск по id или name
/// </summary>
[TestMethod]
public void TestMethod5()
{
#region Fake
MyCollection<MyId, MyElement> collection = new MyCollection<MyId, MyElement>();
for (int i = 1; i < 10; i++)
{
MyElement el = new MyElement()
{
Id = new UserType() { Content = i },
Name = String.Format("Unit - {0}", i)
};
MyId mid = new MyId(el);
collection.Add(mid, el);
}
#endregion
MyElement lostAndFound = collection.GetElementByIdOrName("Unit - 5");
Assert.AreNotEqual(null, lostAndFound);
}
/// <summary>
/// Потокобезопасность - проверка одновременной вставки
/// </summary>
[TestMethod]
public void TestMethod6()
{
#region Fake
MyCollection<MyId, MyElement> collection = new MyCollection<MyId, MyElement>();
for (int i = 1; i < 10; i++)
{
MyElement el = new MyElement()
{
Id = new UserType() { Content = i },
Name = String.Format("Unit - {0}", i)
};
MyId mid = new MyId(el);
collection.Add(mid, el);
}
#endregion
MyElement newElement = new MyElement()
{
Id = new UserType() { Content = 10 },
Name = String.Format("Unit - {0}", 10 )
};
int initCount = collection.Count;
Action<object> action = (object obj) =>
{
collection.Add(new MyId(newElement), newElement);
};
t.Task t1 = new t.Task(action,"thread1");
t.Task t2 = new t.Task(action, "thread2");
t.Task t3 = new t.Task(action, "thread3");
t1.Start();
t2.Start();
t3.Start();
t1.Wait();
t2.Wait();
t3.Wait();
Assert.AreEqual(initCount + 1, collection.Count);
}
Не было просто серьезной мотивации для решения более серьезного, если честно.
Так как делалось все довольно быстро — то куда ж без хаоса.
На счет не выполняется — это Вы зря. Я же только описание классов привел.
На счет последнего вопроса — да. А Вы? Никогда не доводилось писать быстро? Или даже в таких случаях у Вас все идеально? )))
N>Полкода лишние и он не делает то, что должен. Даже близко. Много очевидных опечаток. Общий хаос в коде. N>Рекомендую внимательнее прочесть задание и сделать значительно больше усилий над разработкой. N>А вы уже работали программистом?
M>Этот вариант решения, как видно, не понравился проверявшему. M>Буду признателен, если "ткнете носом" в ошибки. Понимаю, что, возможно подошел к решению довольно формально, но по требованиям вроде все реализовал. Или чего-то не так понял.
Здравствуйте, mig84, Вы писали:
M>Не было просто серьезной мотивации для решения более серьезного, если честно. M>Так как делалось все довольно быстро — то куда ж без хаоса.
Здесь проглядываются довольно простые ошибки, которые опечатками не объяснишь. Код слабоват.
M>На счет последнего вопроса — да. А Вы? Никогда не доводилось писать быстро? Или даже в таких случаях у Вас все идеально? )))
А зачем тогда было отправлять? Если неохота тратить своё время, то лучше не делать тестовое задание. Но взяться делать и при этом вполсилы это как то совсем странно. Либо попадёшь в плохую контору (где требуют тестовые задания несмотря на то, что здесь все стонут, но при этом не проверяют их, либо их устраивает посредственное качество), либо гарантированно потеряешь время.
Здравствуйте, alzt, Вы писали:
A>Здравствуйте, samius, Вы писали:
A>тоже про equals напишу.
A>
A>public override bool Equals(object obj)
A>{
A> if (!(obj is MyElement))
A> {
A> MyElement el = (MyElement)obj; //NULL
A> return Id == el.Id && Name == el.Name; //БАБАХ new NullReferenceException();
A> }
A>
Добавл комменты.
A>Может я совсем C# уже забыл, но что вернёт obj is MyElement если obj имеет тип MyElement?
Ты ничего не забыл.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Всё сказанное выше — личное мнение, если не указано обратное.
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Философ, Вы писали:
Ф>>Здравствуйте, alzt, Вы писали:
A>>>
A>>>public override bool Equals(object obj)
A>>>{
A>>> if (!(obj is MyElement))
A>>> {
A>>> MyElement el = (MyElement)obj; //NULL
A>>> return Id == el.Id && Name == el.Name; //БАБАХ new NullReferenceException();
A>>> }
A>>>
Ф>>Добавл комменты. S>По-моему они еще больше запутывают. Это для прикола, или это прогнозируемые значения и события?
И первое, и второе.
00 if (!(obj is MyElement)) //условие истинно, если obj не является типом MyElement — восклицательный знак всё портит
10 MyElement el = (MyElement)obj; // в шарпе это вообще не выполнится — вывалится с InvalidCastException. Чтобы выполнилось можно кастовать с помощью оператора as
10 MyElement el = obj as MyElement; //а вот так выполнится, el будет равен NULL
20 return Id == el.Id && Name == el.Name; //оращение к полю неинициализированного объекта вывалит исключение NullReferenceException()
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Всё сказанное выше — личное мнение, если не указано обратное.
Здравствуйте, Философ, Вы писали:
Ф>Здравствуйте, samius, Вы писали:
S>>По-моему они еще больше запутывают. Это для прикола, или это прогнозируемые значения и события?
Ф>И первое, и второе.
Ф>00 if (!(obj is MyElement)) //условие истинно, если obj не является типом MyElement — восклицательный знак всё портит
Ф>10 MyElement el = (MyElement)obj; // в шарпе это вообще не выполнится — вывалится с InvalidCastException. Чтобы выполнилось можно кастовать с помощью оператора as
С этим согласен. Но потому как в коде не as, обсуждать остальное смысла нет.