Search code examples
c#abstract-classmember

C# get member 'themember' from class instance T of interface I


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


Solution

  • 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);