#c# #generics #.net-4.0 #refactoring
#c# #общие элементы #.net-4.0 #рефакторинг
Вопрос:
Учитывая список из возможных 5 элементов, приведенный ниже метод вернет новый список ровно из 5 элементов (добавляя больше элементов, если в исходном списке их меньше 5). Это работает нормально, но теперь мне нужно реорганизовать его, чтобы он мог обрабатывать универсальный список T (тот, который будет иметь те же свойства year и Cnt). Как я могу преобразовать этот метод для получения списка и заставить его возвращать новый список с 5 элементами?
private static List<FiveYearComplex> CreateFiveYearTemplate(int startYear,
int endYear, ObjectResult<FiveYearComplex> result)
{
var list = new List<FiveYearComplex>(5);
for (int year = startYear; year < endYear; year)
{
list.Add(new FiveYearComplex() { Year = year, Cnt = 0 });
}
FiveYearComplex tmpItem;
foreach (var item in result)
{
tmpItem = list.Find(w => w.Year == item.Year);
if (tmpItem == null)
{
tmpItem = new FiveYearComplex() { Cnt = 0, Year = item.Year };
}
else
{
tmpItem.Cnt = item.Cnt;
}
}
return list;
}
Когда я пытаюсь использовать List, я в конечном итоге натыкаюсь на этот раздел:
for (int year = startYear; year < endYear; year)
{
list.Add(new T() { Year = year, Cnt = 0 });
}
и я получаю сообщение об ошибке…
Спасибо!
Для полноты картины:
public interface IYearTemplate
{
int? Year { get; set; }
decimal? Cnt { get; set; }
}
private static List<T> CreateFiveYearTemplate <T> (
int startYear, int endYear,
ObjectResult<FiveYearAttendanceComplex> result)
where T : IYearTemplate, new()
{
var list = new List<T>(5);
for (int year = startYear; year < endYear; year)
{
list.Add(new T() { Year = year, Cnt = 0 });
}
T tmpItem;
foreach (var item in result)
{
tmpItem = list.Find(w => w.Year == item.Year);
if (tmpItem == null)
{
tmpItem = new T() { Cnt = 0, Year = item.Year };
}
else
{
tmpItem.Cnt = item.Cnt;
}
}
return list;
}
Спасибо вам.
Комментарии:
1. Вы почти ответили на это <T> и просто вернули другой <T>
2. но когда я пытаюсь сделать new T() { Year = год… Я получаю сообщение об ошибке…
3. Вы же понимаете, что количество элементов в вашем списке основано на значениях
startYear
иendYear
, а не на том факте, что вы инициализируете список емкостью 5, верно?
Ответ №1:
Вы не можете легко преобразовать свой метод для обработки универсального списка, потому что ваш метод не является универсальным. Для этого требуется, чтобы у каждого элемента в списке были свойства Cnt
и Year
, чтобы ваш метод был универсальным, вы должны добавить это ограничение.
public interface IYearTemplate
{
int Cnt {get;set;}
int Year {get;set;}
}
Также для вашего метода требуется конструктор по умолчанию, который выражается как ограничение new()
— так что это может выглядеть следующим образом:
private static List<T> CreateFiveYearTemplate<T>(int startYear,
int endYear, ObjectResult<T> result) where T: IYearTemplate, new()
{
var list = new List<T>(5);
for (int year = startYear; year < endYear; year)
{
list.Add(new T() { Year = year, Cnt = 0 });
}
T tmpItem;
foreach (var item in result)
{
tmpItem = list.Find(w => w.Year == item.Year);
if (tmpItem == null)
{
tmpItem = new T() { Cnt = 0, Year = item.Year };
}
else
{
tmpItem.Cnt = item.Cnt;
}
}
return list;
}
Сказав, что этот метод выглядит не очень общим, поскольку ограничения очень специфичны. Почему вы хотите сделать его универсальным?
Комментарии:
1. Ну, я удалил весь словарь домена из этого примера, чтобы упростить его, но у меня будет несколько объектов, которым нужно будет возвращать список с 5 годами и 5 значениями (cnt).
2. Я все еще не уверен в ваших требованиях — итак, вы имеете дело с разными типами списков или все они возвращаются
List<FiveYearComplex>
— если в последнем случае вам не нужны универсальные элементы.3. Спасибо за ответ. Универсальные элементы так полезны! Я определяю. нужно подробнее ознакомиться с этим.
4. Я имею дело с несколькими различными типами списков, такими как: FiveYearCarComplex, FiveYearTruckComplex, FiveYearSUVComplex. Сложный относится к сложному типу, созданному в результате импорта хранимой процедуры с помощью entity framework фу
Ответ №2:
Чтобы это работало для произвольного T
, у вас было два варианта:
- добавьте
where T : SomeType
ограничение, гдеSomeType
либо базовый класс, либо (что более вероятно и универсально) интерфейс, который объявляет нужные вам свойства - переключитесь на использование
dynamic
(или отражение до версии 4.0) для доступа к свойствам
Первый обеспечивает безопасность во время компиляции, но требует некоторой общности между T
; второй не требует общности, но полностью выполняется во время выполнения — без проверки статическим анализом.
Например:
interface IRenameThis {
int Year {get;set;}
int Cnt {get;set;}
}
И добавить where T : IRenameThis
в сигнатуру метода (между закрытием )
параметров и открытием {
тела метода)
Комментарии:
1. Спасибо за объяснение. Я не мог заставить его работать без использования new
2. @что угодно — о, верно — вам понадобится
where T : IRenameThis, new()
тогда — обратите внимание наnew()
Ответ №3:
static List<T> CreateFiveYearTemplate( int startYear
,int endYear
,ObjectResult<T> result)
where T : FiveYearComplex, new()
{
...
}