Sampath
Sampath

Reputation: 65958

Generic method gives error

I have tried to write a generic method for the below mentioned code snippet.But it gives error on the OrderBy clause ? Could you tell me why ?

var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<StateListDto>>(cache.StringGet(AppConsts.States));
if (values != null) return new ListResultOutput<StateListDto>(values.OrderBy(o => o.Name).ToList());

Generic method :

 public ListResultOutput<T> GetCache<T>(string cacheKey)
   {
      var cache = RedisConnectorHelper.Connection.GetDatabase();
      var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
      return values != null ? new ListResultOutput<T>(values.ToList().OrderBy(o=>o.Name)) : null;
   }

call :

var values = GetCache<StateListDto>(AppConsts.States);

StateListDto.cs

 public class StateListDto 
    {
        public string Code { get; set; }
        public string Name { get; set; }
    }

It gives this error: (click to see the full size image)

enter image description here

Upvotes: 0

Views: 146

Answers (3)

orlevii
orlevii

Reputation: 507

You can send the way you want to order by as a parameter like this:

public ListResultOutput<T> GetCache<T>(string cacheKey, Func<T,object> selector)
{
    var cache = RedisConnectorHelper.Connection.GetDatabase();
    var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
    return values != null ? new ListResultOutput<T>(values.OrderBy(selector).ToList()) : null;
}

call :

GetCache<StateListDto>("yourKey", i=>i.Name);

In this way you don't force your class to implement anything - and you can choose to order by other parameter in your code

Upvotes: 1

David
David

Reputation: 219037

But all are having Name property.

Then create a common interface for them, something like this:

public interface INamed
{
    string Name { get; }
}

And all your models with that property can implement that interface:

public class StateListDto : INamed

Then you can use that interface as a type constraint on the generic method:

public ListResultOutput<T> GetCache<T>(string cacheKey) where T: INamed

That way the compiler can guarantee that the type of T will have a Name property.

Note that a base class, concrete or abstract, can also be used to accomplish this. Though personally I prefer to use interfaces over inheritance unless there's a specific reason to use inheritance.

Upvotes: 1

Bijington
Bijington

Reputation: 3751

If you are expecting to use this for more than just StateListDto I would suggest creating an interface or base class that does have the property called Name then you can guarantee it exists.

Something like:

public interface IDto
{
    string Name { get; }
}

and then you can change your method to:

public ListResultOutput<T> GetCache<T>(string cacheKey) where T: IDto
{
    var cache = RedisConnectorHelper.Connection.GetDatabase();
    var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
    return values != null ? new ListResultOutput<T>(values.ToList().OrderBy(o=>o.Name)) : null;
}

Upvotes: 2

Related Questions