3

how can i make this method generic? How should i reflect the Stock_ID to this method?Thanks in Advance

public class LocalSQL<T> where T : new() 
{
    public static async Task<List<T>> GETLAST( )
    {                    
        return await conn.Table<T>()
            .OrderByDescending(x => x.Stock_ID)
            .Take(10)
            .ToListAsync();
    }
}
Rufus L
  • 36,127
  • 5
  • 30
  • 43
Fethullah Kaya
  • 194
  • 4
  • 16
  • 2
    How do you know `T` has a `Stock_ID` property? – John Wu Apr 28 '20 at 02:23
  • 1
    You have to add a constraint on `T` to some class or interface that has a `Stock_ID` property (which doesn't sound like a great candidate for generics) – Rufus L Apr 28 '20 at 02:26
  • @JohnWu Stock_ID is sembolyzing the any ID. i m asking weather while calling this method can i also set the Id property? – Fethullah Kaya Apr 28 '20 at 02:29
  • 1
    In that case, how do you know `T` has *any* ID? – John Wu Apr 28 '20 at 02:33
  • @JohnWu i will use this method only tables which have id – Fethullah Kaya Apr 28 '20 at 02:39
  • @FkBey But what's to stop me creating an instance of `new LocalSQL();`? C# is a _statically typed_ language, meaning that it needs to be able to check type compatibility at compile time. – ProgrammingLlama Apr 28 '20 at 02:39
  • 1
    In that case you need some way to tell the compiler that you will use this method only on tables which have an ID. Otherwise it has no way of knowing, and it assumes you want to be able to use the method on *any* type. Think you will need to add an interface and a type constraint. – John Wu Apr 28 '20 at 02:40

2 Answers2

5

The generic constraints require you to specify the interface or parent class for the generic type. Try this

public interface IStock
{
    long Stock_ID { get; set; }
}


public class LocalSQL<T> where T : IStock, new()
{
    public static async Task<List<T>> GETLAST( )
    {                    
        return await conn.Table<T>()
            .OrderByDescending(x => x.Stock_ID)
            .Take(10)
            .ToListAsync();
    }
}
Kirin Yao
  • 1,606
  • 2
  • 14
  • 21
5
public class LocalSQL<T> where T : new() 
{
    public static async Task<List<T>> GETLAST(Expression<Func<T, TKey>> key)
    {                    
        return await conn.Table<T>()
            .OrderByDescending(key)
            .Take(10)
            .ToListAsync();
    }
}

This way you can specify only the id to order by in your method.

GETLAST(x => x.StockId)

This answers your question on how to pass an id when calling a method. What I think you want is to have this wrapper over tables to get things by id but your tables have differently named id's so you can't just make one "IStock" interface.

But using this, you can have an interface that returns that expression instead, and make your tables implement the interface. This way you have a generic interface, generic implementation, and tables can give you differently named id's.

Tried implementing, something like this:

public class StockTable : IWithId<StockTable>
{
    public long Stock_Id { get; set; }

    public Expression<Func<StockTable, long>> IdExpression => x => x.Stock_Id;
}

public interface IWithId<T>
{
    Expression<Func<T, long>> IdExpression { get; }
}

public class LocalSQL<T> where T : IWithId<T>, new()
{
    public static async Task<List<T>> GETLAST()
    {
        var obj = new T();

        return await conn.Table<T>()
            .OrderByDescending(obj.IdExpression)
            .Take(10)
            .ToList();
    }
}

It feels a bit awkward, but I think something like this should work. You can try some different approaches, e.g. if you control how LocalSQL is created(as in through a factory and not directly in the code), you could have logic there that correctly builds LocalSQL object, and gives it the correct expression(you have a dictionary of types mapping to expression), this way there's no interfaces, you can access it from a static context without initiating an object, and all of the logic specific to LocalSQL and table mappings would be in the LocalSQL factory.

Erndob
  • 2,512
  • 20
  • 32
  • yes this is what i want exactly. But i couldnt understand the TKey. Despite adding the System.Linq.Expressions , visual studio still can not find the Tkey – Fethullah Kaya Apr 28 '20 at 03:13
  • 1
    I've tried giving it a go, updated my answer. Visual Studio doesn't give errors. – Erndob Apr 28 '20 at 03:32