I have an abstract GetAsync call in a web API to get all types of classes. (actual services with specific code required by a class would derive from this abstract definition) Lets say I'm using Injected MemoryCache to temporaritly replace the DB to test this:
public async Task<IEnumerable<T>> GetAsync()
{
if (!memoryCache.TryGetValue(typeof(T).Name, out List<T>? dtoStuff))
{
dtoStuff = new List<T>();
}
return dtoStuff;
}
This works great to return a list of any such object.
All type 'T' objects are based off of the same Interface
public interface ITheObjectInterface
{
}
public class TheObject : ITheObjectInterface
{
...
}
Now, I want to get a specific item by 'id', and I know ALL types of 'T' have a member that is defined as :
public string? Id { get; set; }
But that's not in the existing ITheObjectInterface that the classes are based off of.
My abtract call is :
public async Task<T> GetAsync(string id)
{
// but how do I access the 'Id' member of any List of type 'T'?
if (!memoryCache.TryGetValue(typeof(T).Name, out List<T>? dtoStuff))
{
dtoStuff = new List<T>();
}
return dtoStuff.FirstOrDefault(o => o.Id== id);
// ^^^^^^^^^^^^^^^^^ error
This has probably been answer 'n' times, but I can't find any answer... so just push me in the right direction
If you can't add Id
to the interface then I suppose you could use Reflection to get it and set it. Perhaps you could write a couple extension methods on ITheObjectInterface
:
static class ExtensionMethods
{
public static string GetId<T>(this T source) where T : ITheObjectInterface
{
return (string)source.GetType().GetProperty("Id")?.GetValue(source);
}
public static void SetId<T>(this T source, string newValue) where T : ITheObjectInterface
{
var property = source.GetType().GetProperty("Id");
if (property == null) throw ArgumentException();
property.SetValue(source, newValue);
}
}
Then you can do something like this:
return dtoStuff.FirstOrDefault(o => o.GetId() == id);