简体   繁体   中英

Only get base class properties, not inheriting class, using reflection

How can I use reflection to only get properties in a base class, not the inherited class.

Say my base class has a virtual method and the inheriting class overrides it. If the override calls base.MyMethod() then reflection within base.MyMethod() gets the properties from both classes or just the inheriting class, depending upon the BindingFlags are used.

Is there a way I can only access the properties in the base class?

Edit: Maybe some code will help explain why I want to do this.

internal static void Save(DataTransactionAccess data, string sproc, object obj)
{
  if (checkMandatoryProperties(obj))
  {
    saveToDatabase(data, sproc, obj);
  }
}

private static void saveToDatabase(DataTransactionAccess data, string sproc, object obj)
{
  List<object> paramList;
  PropertyInfo idProperty;
  populateSaveParams(out paramList, out idProperty, obj);
  if (idProperty != null)
  {
    int id = data.ExecuteINTProcedure(sproc, paramList.ToArray());
    idProperty.SetValue(obj, id, null);
  }
  else
  {
    data.ExecuteProcedure(sproc, paramList.ToArray());
  }
}

private static void populateSaveParams(out List<object> paramList, out PropertyInfo idProperty, object obj)
{
  paramList = new List<object>();
  idProperty = null;
  foreach (PropertyInfo info in obj.GetType().GetProperties())
  {
    if (info.GetCustomAttributes(typeof(SaveProperty), true).Length > 0)
    {
      paramList.Add("@" + info.Name);
      paramList.Add(info.GetValue(obj, null));
    }
    if (info.GetCustomAttributes(typeof(SaveReturnIDProperty), true).Length > 0)
    {
      idProperty = info;
    }
  }
}

It is within the foreach loop in populateSaveParams that I need to get the properties for the class within obj that Save was called, not any classes it inherits from or any of its child classes.

Hope this makes it clearer.

I came across a scenario where I needed a method to perform decision making based only on the base class properties.

So I filtered the properties of the instance this can be done in one of two ways as shown below,

Using the BaseType property on the Type and then call the GetProperties method,

var baseType = instance.GetType().BaseType;
var properties = baseType.GetProperties();

Using the DeclaringType property to check whether it is from the base class or the derived class,

var type = instance.GetType();
var properties = type.GetProperties();
// properties = properties.Where(p => p.DeclaringType.FullName == typeof(SomeClass).FullName).ToArray();
properties = properties.Where(p => p.DeclaringType.FullName == type.BaseType.FullName).ToArray();

The below code snippet retrieves the base class properties and writes them to the output stream. Here is the compile C# online link

using System;
using System.Linq;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Employee (derived class) - Person (base class)
            var employee = new Employee
            {
                Company = "Stack Overflow",
                Designation = "Community Manager",
                FirstName = "Josh",
                LastName = "Heyer"
            };

            var baseType = employee.GetType().BaseType;
            var properties = baseType.GetProperties();
            var method = baseType.GetMethod("Print");

            for (var i = 0; i < properties.Count(); i++)
            {
                Console.WriteLine(properties[i].Name);
            }

            Console.WriteLine();
            method.Invoke(employee, null);
        }
    }

    public class Person
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        public virtual void Print()
        {
            Console.WriteLine("Name: {0} {1}", FirstName, LastName);
        }
    }

    public class Employee : Person
    {
        public string Company { get; set; }

        public string Designation { get; set; }

        public override void Print()
        {
            base.Print();
            Console.WriteLine("Employment Details: {0} {1}", Company, Designation);
        }
    }
}

It sounds to me like a little bit of restructuring would be in order. Anything implementing the Interface would return a set of save operations:

public interface ISomeInterface
{
     IEnumerable<SaveStep> SaveData();
}

public class SomeClass : SomeBaseClass, ISomeInterface
{
    public virtual IEnumerable<SaveStep> SaveData()
    {
        foreach(var item in base.SaveData())
           yield return item;

        yield return new SaveStep { ... }
    }
}

Then you extension method (or any invoker really) just needs to invoke the SaveData method, and you get back a set of SaveStep objects you can use to constuct a procedure call with data based on whatever that class wanted.

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