简体   繁体   中英

Reflection using generics

I'd like to return the properties of a series of DbSet objects I have saved to a class using reflection, but in order to access this data in a single method I'd need to pass a variable as an accessor to return the properties of that object.

Currently I've managed to return the properties of all of the DbSet objects, but the code looks very DRY.

public DbSet<Foo> Foo {get;set;}
public DbSet<Bar> Bar {get;set;}

public List<string> GetPropertiesFoo()
{
    DbContext client = new DbContext();
    return client.Foo.GetType().GetProperties().Select(e => e.Name).ToList();
}
public List<string> GetPropertiesBar()
{
    DbContext client = new DbContext();
    return client.Bar.GetType().GetProperties().Select(e => e.Name).ToList();
}

My intention is to refactor this so that it accepts a DbSet name as an argument and returns a single list of properties, rather than a list of all properties.

You are looking for something like this to do it all in one hit. Note this code is quite verbose so that each step can be explained:

// Make the method generic so we can use it on any context
public List<string> GetProperties<TContext>(string dbSetName = "")
    where TContext : DbContext // Make sure we have a Dbcontext
{
    var propertyNames = typeof(TContext)

        // Get all properties of context
        .GetProperties() 

         // Filter out so we only have DbSet<> types
        .Where(pi => pi.PropertyType.IsGenericType &&
                     typeof(DbSet<>).IsAssignableFrom(pi.PropertyType.GetGenericTypeDefinition()))

        // If a DbSet name has been specified, filter it out
        .Where(pi => string.IsNullOrEmpty(dbSetName) || pi.Name == dbSetName)

        // Get the generic type e.g. Foo
        .Select(pi => pi.PropertyType.GetGenericArguments()[0])

        // Get the individual properties of the entity types
        .Select(t => t.GetProperties())

        // Get all of the property names
        .SelectMany(x => x.Select(pi => pi.Name)); 

    return propertyNames.ToList();
}

And use it like this:

// All properties for all sets
var allProperties = GetProperties<MyContext>();

// Only properties for the Foo set
var fooProperties = GetProperties<MyContext>("Foo");

I think you might be after something like this

public List<string> GetProperties(string model)
{
   var property = 
      this.GetType()
      .GetProperties()
      .Where(p=>p.Name == model)
      .FirstOrDefault();

   if(property == null) return IEnumerable.Empty<string>().ToList();
   return property
      .PropertyType
      .GetGenericArguments()[0]
      .GetProperties()
      .Select(p=>p.Name)
      .ToList();
}
public List<Foo> GetFooFromBar(string bar)
{
     return = typeof(FooContext)//a list of DbSets (DbSet<Foo>, DbSet<Bar>)
    .GetProperties()
    .Where(e => e.Name == bar)//Filter based on the name of DbSet entered
    .GetType()//Get Type of the object returned (the DbSet with a matching name)
    .GetGenericArguments()[0]//Get the first item in the array of PropertyInfo
    .GetProperties()//Get a list of the properties of the DbSet within the Context
    .ToList();
    return bar;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM