【问题标题】:Only get base class properties, not inheriting class, using reflection只获取基类属性,不继承类,使用反射
【发布时间】:2012-04-24 18:04:17
【问题描述】:

如何使用反射仅获取基类中的属性,而不是继承的类。

假设我的基类有一个虚方法,而继承类覆盖了它。如果覆盖调用 base.MyMethod() 则 base.MyMethod() 中的反射从两个类或仅继承类获取属性,具体取决于使用的 BindingFlags。

有没有办法只能访问基类中的属性?

编辑:也许一些代码可以帮助解释我为什么要这样做。

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;
    }
  }
}

在 populateSaveParams 的 foreach 循环中,我需要获取调用 Save 的 obj 中的类的属性,而不是它继承自的任何类或其任何子类。

希望这能让它更清楚。

【问题讨论】:

  • 在检查值时您使用的是GetType 还是typeof(BaseClass)?我认为后者只会得到你的基类值。
  • 我不能使用 typeof(BaseClass) 因为这是一个接口的扩展方法,所以需要在运行时使用 GetType() 确定底层类。
  • 如果你的扩展方法只知道接口,为什么还要关心基类呢?听起来你的扩展方法太宽泛了。
  • 扩展方法创建对保存存储过程的调用,具体取决于用自定义属性修饰的属性。通常这可以正常工作,但我要求类的层次结构有自己的存储过程,并且只保存在要考虑的各个类中声明的属性。
  • 所以类型层次结构中的每个单独类型都有自己的保存步骤?

标签: c#


【解决方案1】:

我遇到了一个场景,我需要一种方法来执行仅基于基类属性的决策。

所以我过滤了实例的属性,这可以通过如下所示的两种方式之一来完成,

使用Type上的BaseType属性,然后调用GetProperties方法,

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

使用DeclaringType属性判断是来自基类还是派生类,

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

下面的代码 sn-p 检索基类属性并将它们写入输出流。 Here是编译C#在线链接

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

【讨论】:

  • 考虑发布一个修改后的答案,目前它看起来就像一个代码转储,我怀疑有人有时间筛选它以找到相关信息
  • @TheLethalCoder,感谢您的建议,我已经更新了我的答案
【解决方案2】:

在我看来,应该进行一些重组。任何实现接口的东西都会返回一组保存操作:

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 { ... }
    }
}

然后你的扩展方法(或任何调用者)只需要调用SaveData 方法,然后你会返回一组SaveStep 对象,你可以根据该类想要的任何数据来构造一个过程调用.

【讨论】:

  • 感谢您的建议,我会在以后的工作中考虑它。但是,我仍然想知道如何实现我在原始问题中提出的问题。
  • 我能想到的唯一其他方法是检查GetType() 并递归解析Type.BaseType 属性,而它是!= typeof(object),然后使用该引用来解析它的属性。跨度>
  • 是的,可以,但我想我宁愿写更大、更复杂的存储过程,而不是使用接口快捷方式。直接做与我想要的相反的事情似乎有点愚蠢,只获取继承类的属性,但这样不容易。
  • 嗯,从技术上讲,你不能做相反的事情吗?如果您有一个所有属性 X 的列表,然后是仅派生属性 Y 的列表,那么理论上您可以对 X 和 Y 的集合进行非交集。但这将是 一切不是你最衍生的类型。
  • 是的,但是如果类层次结构是任意大小的,它就会变得非常丑陋。我现在正在研究的那个有三个级别,但其他级别可能更大。我不认为这是一种使用递归会开花的技术!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
  • 2018-06-05
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 1970-01-01
相关资源
最近更新 更多