Search code examples
c#listgenericstypesinstance

How do you pass and use a generic Type with a method?


In terms of the DRY principle, I'm seeking to reduce the methods below (there are other lists that need generating, so number is larger in real life):

public static List<Genre> GetGenres(ApiCredentials apiCredentials = null, ApiServerParameters apiServerParameters = null)
{
    List<Genre> returns = new List<Genre>();

    GetData getData = new GetData(apiCredentials, apiServerParameters);
    var outcome = getData.GetListOrInfo(Enums.ApiQueryType.GenreList);

    XDocument xdoc = XDocument.Parse(outcome.Data.ToString());
    
    foreach (var genre in xdoc.Descendants("genre"))
    {
        returns.Add(new Genre(genre));
    }       

    return returns;
}

public static List<Language> GetLanguages(ApiCredentials apiCredentials = null, ApiServerParameters apiServerParameters = null)
{
    List<Language> returns = new List<Language>();

    GetData getData = new GetData(apiCredentials, apiServerParameters);
    var outcome = getData.GetListOrInfo(Enums.ApiQueryType.LanguageList);

    XDocument xdoc = XDocument.Parse(outcome.Data.ToString());

    foreach (var language in xdoc.Descendants("langue"))
    {
        returns.Add(new Language(language));
    }

    return returns;
}

I've figured out how to pass a generic T, but cannot figure how to raise a new instance of Type T:

public static List<T> GetList<T>(Enums.ApiQueryType queryType, string xElementName,
    ApiCredentials apiCredentials = null, ApiServerParameters apiServerParameters = null)
{

    List<T> returns = new List<T>();

    GetData getData = new GetData(apiCredentials, apiServerParameters);
    var outcome = getData.GetListOrInfo(queryType);

    XDocument xdoc = XDocument.Parse(outcome.Data.ToString());

    foreach (var element in xdoc.Descendants(xElementName))
    {
        returns.Add(new T(element)); /// Doesn't compile
    }

    return null;
}

How do I do this?

==========================================

ANSWER: Thanks to all the helpful replies - this put me on the right track. The best approach I found for me (in terms of readability and simplicity):

public static List<T> GetList<T>(Enums.ApiQueryType queryType, string xElementName,
    ApiCredentials apiCredentials = null, ApiServerParameters apiServerParameters = null)
{

    List<T> returns = new List<T>();

    GetData getData = new GetData(apiCredentials, apiServerParameters);
    var outcome = getData.GetListOrInfo(queryType);

    XDocument xdoc = XDocument.Parse(outcome.Data.ToString());

    foreach (var element in xdoc.Descendants(xElementName))
    {
        var obj = (T)Activator.CreateInstance(typeof(T), element);
        returns.Add(obj);
    }

    return returns;
}


Solution

  • Either add a constraint on T's constructor, however, unless this has recently changed, this won't work for a constructor with parameters. I.e. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-constraint

    or

    use reflection to retrieve a constructor for T that has one parameter of the type you want to pass. E.g. https://stackoverflow.com/a/3255716/38368