Jak mogę utworzyć wystąpienie typu T w mojej InstantiateType<T>
metodzie poniżej?
Pojawia się błąd: „T” to „parametr typu”, ale jest używany jako „zmienna”. :
(PRZEWIŃ W DÓŁ, ABY ODPOWIEDZIĆ NA PONOWNIE)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGeneric33
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
Console.WriteLine(container.InstantiateType<Customer>("Jim", "Smith"));
Console.WriteLine(container.InstantiateType<Employee>("Joe", "Thompson"));
Console.ReadLine();
}
}
public class Container
{
public T InstantiateType<T>(string firstName, string lastName) where T : IPerson
{
T obj = T();
obj.FirstName(firstName);
obj.LastName(lastName);
return obj;
}
}
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
public class Customer : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
}
public class Employee : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int EmployeeNumber { get; set; }
}
}
ODPOWIEDŹ ODNOWIONA:
Dzięki za wszystkie komentarze, doprowadzili mnie do właściwej ścieżki, oto co chciałem zrobić:
using System;
namespace TestGeneric33
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
Customer customer1 = container.InstantiateType<Customer>("Jim", "Smith");
Employee employee1 = container.InstantiateType<Employee>("Joe", "Thompson");
Console.WriteLine(PersonDisplayer.SimpleDisplay(customer1));
Console.WriteLine(PersonDisplayer.SimpleDisplay(employee1));
Console.ReadLine();
}
}
public class Container
{
public T InstantiateType<T>(string firstName, string lastName) where T : IPerson, new()
{
T obj = new T();
obj.FirstName = firstName;
obj.LastName = lastName;
return obj;
}
}
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
public class PersonDisplayer
{
private IPerson _person;
public PersonDisplayer(IPerson person)
{
_person = person;
}
public string SimpleDisplay()
{
return String.Format("{1}, {0}", _person.FirstName, _person.LastName);
}
public static string SimpleDisplay(IPerson person)
{
PersonDisplayer personDisplayer = new PersonDisplayer(person);
return personDisplayer.SimpleDisplay();
}
}
public class Customer : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
}
public class Employee : IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int EmployeeNumber { get; set; }
}
}
Odpowiedzi:
Zadeklaruj swoją metodę w następujący sposób:
Zwróć uwagę na dodatkowe ograniczenie na końcu. Następnie utwórz
new
instancję w treści metody:źródło
Na kilka sposobów.
Bez określenia typu musi mieć konstruktora:
Z konstruktorem:
Ale to wymaga klauzuli:
źródło
Aby rozszerzyć powyższe odpowiedzi, dodanie
where T:new()
ograniczenia do metody ogólnej będzie wymagało od T posiadania publicznego konstruktora bez parametrów.Jeśli chcesz tego uniknąć - i zgodnie ze wzorcem fabrycznym czasami zmuszasz innych do przejścia przez twoją metodę fabryczną, a nie bezpośrednio przez konstruktora - alternatywą jest użycie refleksji (
Activator.CreateInstance...
) i zachowanie domyślnego konstruktora jako prywatnego. Ale wiąże się to oczywiście ze spadkiem wydajności.źródło
chcesz nowe T (), ale musisz też dodać
, new()
dowhere
specyfikacji dla metody fabrycznejźródło
Trochę stary, ale dla innych szukających rozwiązania, może to być interesujące: http://daniel.wertheim.se/2011/12/29/c-generic-factory-with-support-for-private-constructors/
Dwa rozwiązania. Jeden wykorzystujący Activator i jeden wykorzystujący skompilowane lambdy.
źródło
Możesz również użyć odbicia, aby pobrać konstruktor obiektu i utworzyć jego wystąpienie w ten sposób:
źródło
Użycie klasy fabrycznej do zbudowania obiektu za pomocą skompilowanego wyrażenia lamba: najszybszy sposób, jaki znalazłem na tworzenie instancji typu ogólnego.
Oto kroki, które wykonałem, aby skonfigurować test porównawczy.
Utwórz moją metodę testową:
Próbowałem też użyć metody fabrycznej:
Do testów stworzyłem najprostszą klasę:
Skrypt do przetestowania:
Uwagi : Testowałem używając zarówno .NET Framework 4.5, jak i 4.6 (równoważne wyniki).
źródło
Zamiast tworzyć funkcję do tworzenia wystąpienia typu
mogłeś to zrobić w ten sposób
źródło
new()
Twoja odpowiedź zadziałała, nadal konieczne jest ograniczenie typu ogólnego.