c# - parser - html agility pack remove tags




Passando argomenti a C#generico new() di tipo di modello (9)

È necessario aggiungere il punto in cui T: new () per consentire al compilatore di sapere che T è garantito per fornire un costruttore predefinito.

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

Sto cercando di creare un nuovo oggetto di tipo T tramite il suo costruttore quando si aggiunge alla lista.

Ricevo un errore di compilazione: il messaggio di errore è:

'T': non può fornire argomenti durante la creazione di un'istanza di una variabile

Ma le mie classi hanno un argomento costruttore! Come posso fare questo lavoro?

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

È una specie di mucky, e quando dico una specie di mucky potrei dire rivoltante, ma supponendo che tu possa fornire il tuo tipo parametrizzato con un costruttore vuoto, allora:

public static T GetTInstance<T>() where T: new()
{
    var constructorTypeSignature = new Type[] {typeof (object)};
    var constructorParameters = new object[] {"Create a T"};
    return (T) new T().GetType().GetConstructor(constructorTypeSignature).Invoke(constructorParameters);
}

Permetterà effettivamente di costruire un oggetto da un tipo parametrizzato con un argomento. In questo caso sto assumendo che il costruttore che voglio abbia un singolo argomento di tipo object . Creiamo un'istanza fittizia di T usando il costrutto costrutto vuoto consentito e quindi usiamo il reflection per ottenere uno dei suoi altri costruttori.


Credo che devi vincolare T con un'istruzione where per consentire solo oggetti con un nuovo costruttore.

Ora accetta qualsiasi cosa, compresi gli oggetti senza di essa.


Dal momento che nessuno si è preso la briga di pubblicare la risposta "Riflessione" (che personalmente ritengo sia la migliore risposta), ecco qui:

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);
   } 
   ...
}

Modifica: questa risposta è deprecata a causa di .NET 3.5 Activator.CreateInstance, tuttavia è ancora utile nelle versioni .NET precedenti.


Ho scoperto che stavo ricevendo un errore "non è possibile fornire argomenti durante la creazione di un'istanza di tipo parametro T", quindi ho dovuto fare questo:

var x = Activator.CreateInstance(typeof(T), args) as T;

Per creare un'istanza di un tipo generico in una funzione devi vincolarla con il flag "new".

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

Tuttavia ciò funzionerà solo quando si desidera chiamare il costruttore che non ha parametri. Non è il caso qui. Dovrai invece fornire un altro parametro che consente la creazione di oggetti in base ai parametri. Il più semplice è una funzione.

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

Puoi quindi chiamarlo così

GetAllItems<Foo>(..., l => new Foo(l));

Se hai accesso al corso che intendi utilizzare, puoi utilizzare questo approccio che ho utilizzato.

Crea un'interfaccia con un creatore alternativo:

public interface ICreatable1Param
{
    void PopulateInstance(object Param);
}

Crea le tue classi con un creatore vuoto e implementa questo metodo:

public class MyClass : ICreatable1Param
{
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        //populate the class here
    }
}

Ora usa i tuoi metodi generici:

public void MyMethod<T>(...) where T : ICreatable1Param, new()
{
    //do stuff
    T newT = new T();
    T.PopulateInstance(Param);
}

Se non hai accesso, racchiudi la classe di destinazione:

public class MyClass : ICreatable1Param
{
    public WrappedClass WrappedInstance {get; private set; }
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        WrappedInstance = new WrappedClass(Param);
    }
}

Se vuoi semplicemente inizializzare un campo membro o una proprietà con il parametro costruttore, in C #> = 3 puoi farlo molto più facilmente:

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. 
   }  
   ... 
} 

Questa è la stessa cosa che ha detto Garry Shutler, ma vorrei mettere una nota adizionale.

Ovviamente puoi usare un trucco di proprietà per fare più cose che semplicemente impostare un valore di campo. Una proprietà "set ()" può attivare qualsiasi elaborazione necessaria per impostare i relativi campi e qualsiasi altra necessità per l'oggetto stesso, incluso un controllo per verificare se è stata eseguita un'inizializzazione completa prima che l'oggetto venga utilizzato, simulando una completa contruction ( sì, è una brutta soluzione, ma supera la limitazione di ($) di M $).

Non posso assicurarmi se si tratta di un buco pianificato o di un effetto collaterale accidentale, ma funziona.

È molto divertente come M $ le persone aggiungano nuove funzionalità alla lingua e sembra non eseguire un'analisi completa degli effetti collaterali. L'intera cosa generica è una buona prova di questo ...


Inizializzatore dell'oggetto

Se il tuo costruttore con il parametro non sta facendo altro che impostare una proprietà, puoi farlo in C # 3 o meglio usando un inizializzatore di oggetti piuttosto che chiamare un costruttore (che è impossibile, come è stato detto):

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
   } 
   ...
}

Usando questo, puoi sempre inserire qualsiasi logica di costruzione nel costruttore predefinito (vuoto).

Activator.CreateInstance ()

In alternativa, puoi chiamare Activator.CreateInstance() modo:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
        object[] args = new object[] { listItem };
        tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
   } 
   ...
}

Si noti che Activator.CreateInstance può avere un sovraccarico delle prestazioni che si potrebbe voler evitare se la velocità di esecuzione è una priorità assoluta e un'altra opzione è gestibile dall'utente.





new-operator