web-dev-qa-db-fra.com

Impossible de créer une instance du type de variable 'Item' car elle n'a pas la contrainte new ()

J'essaie de tester une méthode - et j'obtiens une erreur:

Cannot create an instance of the variable type 'Item' because it does not have the new() constraint

Informations requises ci-dessous:

public interface IHasRect
{
 Rectangle Rectangle { get; }
}

Classe d'assistance:

class Item : IHasRect
{
  public Item(Point p, int size)
  {
     m_size = size;
     m_rectangle = new Rectangle(p.X, p.Y, m_size, m_size); 
  }
}

Pour que la fonction soit testée, j'ai besoin d'instancier un objet ...

public class SomeClass<T> where T : IHasRect

Le test:

public void CountTestHelper<Item>()
  where Item : IHasRect
  {
    Rectangle rectangle = new Rectangle(0, 0, 100, 100); 
    SomeClass<Item> target = new SomeClass<Item>(rectangle);            
    Point p = new Point(10,10);
    Item i = new Item(p, 10);      // error here        
    ...
  }
[TestMethod()]
public void CountTest()
{
  CountTestHelper<Item>();
}   

J'essaie de comprendre ce que signifie cette erreur, ou comment la corriger, en lisant http://msdn.Microsoft.com/en-us/library/d5x73970.aspx et http : //msdn.Microsoft.com/en-us/library/x3y47hd4.aspx - mais cela n'aide pas.

Je ne comprends pas cette erreur - j'ai déjà contraint le "SomeClass" à être de type. Je ne peux pas contraindre la classe Test entière (la classe de test unitaire générée par Visual Studio, qui contient tous les tests) - sinon, j'obtiendrai un certain nombre d'autres erreurs. La classe Item n'a pas de modèle ...

Veuillez m'aider à corriger cette erreur. Merci.

38
Thalia

Le Item dans la ligne:

Item i = new Item(p, 10);

fait référence au paramètre de type générique Item de la méthode CountTestHelper, pas à la classe Item. Modifiez le nom du paramètre générique, par ex.

public void CountTestHelper<TItem>() where TItem : IHasRect
{
    Rectangle rectangle = new Rectangle(0, 0, 100, 100); 
    SomeClass<TItem> target = new SomeClass<TItem>(rectangle);            
    Point p = new Point(10,10);
    Item i = new Item(p, 10);    
    ...
}

vous pouvez également qualifier entièrement le nom de la classe Item que vous souhaitez créer:

public void CountTestHelper<Item>() where Item : IHasRect
{
    Rectangle rectangle = new Rectangle(0, 0, 100, 100); 
    SomeClass<Item> target = new SomeClass<Item>(rectangle);            
    Point p = new Point(10,10);
    SomeNamespace.Item i = new SomeNamespace.Item(p, 10);  
}
12
Lee

Vous ne pouvez pas initialiser un objet de type générique à moins de le marquer comme implémentant le constructeur par défaut à l'aide du mot clé new:

public void CountTestHelper<Item>() where Item : IHasRect, new()
 {
    Rectangle rectangle = new Rectangle(0, 0, 100, 100); 
    SomeClass<Item> target = new SomeClass<Item>(rectangle);            
    Point p = new Point(10,10);
    Item i = new Item();    // constructor has to be parameterless!
    ...
 }

D'un autre côté, si vous essayez d'initialiser un objet de type Item défini ailleurs dans l'application, essayez d'utiliser namespace avant:

MyAppNamespace.Item i = new MyAppNamespace.Item(p, 10);
109
MarcinJuraszek

Parce que beaucoup de gens arrivent ici par la question tilte (qui est très générique et correspond au message du compilateur), permettez-moi de donner une réponse plus détaillée sur l'erreur de compilation itsef.

Vous utilisez des génériques dans une méthode. Le compilateur ne sait pas quel type il recevra et il n'est donc pas garanti que votre type ait un constructeur sans paramètre. Par exemple:

class A {
    A(int i){ ... }
}

class B { ... }

public void MyMethod<T>(){
    T t = new T(); //This would be fine if you use 'MyMethod<B>' but you would have a problem calling 'MyMethod<A>' (because A doesn´t have a parameterless construtor;
}

Pour résoudre ce problème, vous pouvez indiquer au compilateur que votre paramètre générique a un interpréteur sans paramètre. Cela se fait en définissant des contraintes:

public void MyMethod<T>()  where T: new(){
    T t = new T(); //Now it's ok because compiler will ensure that you only call generic method using a type with parameterless construtor;
}

Plus d'informations sur les contraintes de constructeur peuvent être trouvées ici: https://msdn.Microsoft.com/en-us/library/bb384067.aspx

28
Zé Carlos