Передача аргументов в C # generic new () шаблонного типа

Это должно работать: (редактирование на месте)

import fileinput

# Does a list of files, and
# redirects STDOUT to the file in question
for line in fileinput.input(files, inplace = 1): 
      print line.replace("foo", "bar"),
384
задан Rup 8 March 2012 в 10:22
поделиться

7 ответов

Чтобы создать экземпляр универсального типа в функции, вы должны ограничить его с помощью флага «новый».

public static string GetAllItems<T>(...) where T : new()

Однако это будет работать только тогда, когда вы захотите вызвать конструктор, у которого нет параметров. Здесь не тот случай. Вместо этого вам нужно будет предоставить другой параметр, который позволяет создавать объект на основе параметров. Самый простой - это функция.

public static string GetAllItems<T>(..., Func<ListItem,T> del) {
  ...
  List<T> tabListItems = new List<T>();
  foreach (ListItem listItem in listCollection) 
  {
    tabListItems.Add(del(listItem));
  }
  ...
}

Затем вы можете назвать это так

GetAllItems<Foo>(..., l => new Foo(l));
400
ответ дан 22 November 2019 в 23:44
поделиться

Если все - Вы, потребность является convertion от ListItem до Вашего типа T, можно реализовать этот convertion в классе T как оператор преобразования.

public class T
{
    public static implicit operator T(ListItem listItem) => /* ... */;
}

public static string GetAllItems(...)
{
    ...
    List<T> tabListItems = new List<T>();
    foreach (ListItem listItem in listCollection) 
    {
        tabListItems.Add(listItem);
    } 
    ...
}
0
ответ дан NightmareZ 4 November 2019 в 09:26
поделиться

Это не сработает в вашей ситуации. Вы можете указать только ограничение, что у него есть пустой конструктор:

public static string GetAllItems<T>(...) where T: new()

Что вы могли бы сделать, так это использовать внедрение свойств, определив этот интерфейс:

public interface ITakesAListItem
{
   ListItem Item { set; }
}

Затем вы можете изменить свой метод следующим образом:

public static string GetAllItems<T>(...) where T : ITakesAListItem, new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { Item = listItem });
   } 
   ...
}

Другой альтернативой является Метод Func , описанный JaredPar.

18
ответ дан 22 November 2019 в 23:44
поделиться

Вам нужно добавить where T: new (), чтобы компилятор знал, что T гарантированно предоставит конструктор по умолчанию.

public static string GetAllItems<T>(...) where T: new()
7
ответ дан 22 November 2019 в 23:44
поделиться

Я считаю, что вам нужно ограничить T с помощью оператора where разрешить только объекты с новым конструктором.

ПРАВИЛЬНО теперь он принимает все, включая объекты без него.

-4
ответ дан 22 November 2019 в 23:44
поделиться

Если вы просто хотите инициализировать поле или свойство члена параметром конструктора, в C #> = 3 вы можете сделать это очень просто:

public static string GetAllItems<T>(...) where T : InterfaceOrBaseClass, new() 
{ 
   ... 
   List<T> tabListItems = new List<T>(); 
   foreach (ListItem listItem in listCollection)  
   { 
       tabListItems.Add(new T{ BaseMemberItem = listItem }); // No error, BaseMemberItem owns to InterfaceOrBaseClass. 
   }  
   ... 
} 

Это это то же самое, что сказал Гарри Шатлер, но я хотел бы добавить дополнительное примечание.

Конечно, вы можете использовать уловку свойств, чтобы делать больше, чем просто устанавливать значение поля. Свойство "set ()" может инициировать любую обработку, необходимую для настройки связанных с ним полей, и любую другую потребность в сам объект, включая проверку того, должна ли происходить полная инициализация перед использованием объекта, имитируя полную конструкцию (да, это уродливый обходной путь, но он преодолевает ограничение M $ new ()).

Я не могу с уверенностью сказать, запланированная ли это дыра или случайный побочный эффект, но это работает.

Очень забавно, как MS-люди добавляют новые функции к языку и, кажется, не проводят полного анализа побочных эффектов. Все общие вещи являются хорошим доказательством этого ...

{{ 1}}
7
ответ дан 22 November 2019 в 23:44
поделиться

Поскольку никто не удосужился опубликовать ответ «Отражение» (который я лично считаю лучшим ответом), вот что:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       Type classType = typeof(T);
       ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { listItem.GetType() });
       T classInstance = (T)classConstructor.Invoke(new object[] { listItem });

       tabListItems.Add(classInstance);
   } 
   ...
}

Изменить: этот ответ устарел из-за .NET 3.5. Activator.CreateInstance, однако он по-прежнему полезен в более старых версиях .NET.

51
ответ дан 22 November 2019 в 23:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: