Steve Chadbourne
Steve Chadbourne

Reputation: 6953

C# Generics and inferring type

I'm struggling while trying to write generic methods to save and load data from a Sterling database.

This is my save method:

public static void SaveList<T>(List<T> listToSave)
{
    foreach (T listItem in listToSave)
    {
        DatabaseInstance.Save(listItem);
    }
}

I get squiggly red line under save and an error of "The Type T must be a reference type in order to use it as parameter T"

This is my load method:

    public static List<T> LoadList<T>()
    {
        List<T> list = (from index in DatabaseInstance.Query<T, int>() select index.Key).ToList();

        return list;
    }

I get the same error.

Any ideas?

Cheers

Steve

UPDATE:

I added a where T : class as suggested and got an error:

The Type T must have a public parameterless constructor in order to use it as a parameter

Following instructions in the link provided by Bryan I added , new() on the end and all working now.

Upvotes: 3

Views: 269

Answers (5)

Joel Coehoorn
Joel Coehoorn

Reputation: 415735

To fix your code, you need a generic constraint that forces a reference type, as shown below. To set this answer out from others already posted, I also recommend that you use IEnumerable<T> rather than List<T>:

public static void SaveList<T>(IEnumerable<T> itemsToSave) where T : class
{
    foreach (T item in itemsToSave)
    {
        DatabaseInstance.Save(listItem);
    }
}

public static IEnumerable<T> LoadList<T>() where T : class
{
    return (from index in DatabaseInstance.Query<T, int>()
            select index.Key);
}

The change to IEnumerable<T> should be compatible with all your existing code, as List<T> already implements IEnumerable<T>. Used properly, this will also allow you get a nice performance boost by keeping fewer items at a time in RAM and make your code more powerful by allowing it to work with other collection types.

Upvotes: 4

Enigmativity
Enigmativity

Reputation: 117064

Try adding a class constraint:

public static void SaveList<T>(List<T> listToSave) where T : class
{
    foreach (T listItem in listToSave)
    {
        DatabaseInstance.Save(listItem);
    }
}

public static List<T> LoadList<T>() where T : class
{
    List<T> list = (from index in DatabaseInstance.Query<T, int>()
            select index.Key).ToList();

    return list;
}

Upvotes: 1

rossipedia
rossipedia

Reputation: 59377

You need a generic type constraint on your definition:

public static void SaveList<T>(List<T> listToSave) where T : class
{
    foreach (T listItem in listToSave)
    {
        DatabaseInstance.Save(listItem);
    }
}

public static List<T> LoadList<T>()  where T : class
{
    List<T> list = (from index in DatabaseInstance.Query<T, int>() select index.Key).ToList();
    return list;
}

Upvotes: 4

Andrew Shepherd
Andrew Shepherd

Reputation: 45252

The problem is that, in your existing code, T can be anything. That's not OK because the Save function only accepts reference types.

You need to place a constraint which effectively makes a commitment to the compiler that T will be a reference type.

public static void SaveList<T>(List<T> listToSave) where T : class
{
    foreach (T listItem in listToSave)
    {
        DatabaseInstance.Save(listItem);
    }
}

Upvotes: 2

DarthVader
DarthVader

Reputation: 55032

can you try?

public static void SaveList<T>(List<T> listToSave) where T:class
{
    foreach (T listItem in listToSave)
    {
        DatabaseInstance.Save(listItem);
    }
}

Upvotes: 1

Related Questions