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 d'obtenir une erreur:

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

Informations requises pour CI-DESSOUS:

public interface IHasRect
{
 Rectangle Rectangle { get; }
}

Classe D'aide:

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 il 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 de Test entière (la classe de test unitaire générée par Visual Studio, qui contient tous les tests) - j'obtiendrai un certain nombre d'autres erreurs sinon. La classe de l'Élément n'est pas n'importe quel modèle...

Aidez-moi à corriger cette erreur. Merci.

31
demandé sur Thalia 2013-02-05 02:27:20

3 réponses

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. Modifier le nom du paramètre générique, par exemple

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 complètement 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);  
}
9
répondu Lee 2013-02-04 22:50:31

Vous ne pouvez pas initialiser L'objet de type générique sauf si vous le marquez comme implémentant le constructeur par défaut en utilisant new mot-clé:

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'autre part, si vous essayez d'initialiser Item type d'objet défini ailleurs dans l'application, essayez d'utiliser l'espace de noms avant:

MyAppNamespace.Item i = new MyAppNamespace.Item(p, 10);
90
répondu MarcinJuraszek 2013-02-04 22:32:29

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 interpréteur 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. C'est 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 du constructeur peuvent être trouvées ici: https://msdn.microsoft.com/en-us/library/bb384067.aspx

19
répondu Zé Carlos 2015-03-30 11:40:30