c# - 获取派生类属性的属性或名称

标签 c# generics reflection

我们有一个 BaseClass和一组派生的 POCO 类(参见 DerivedClassA )。它们映射到数据库中我们目前无法更改的现有键值存储。

派生类的每个属性都将映射到商店中的一个键。属性表示的键是字符串值,它们可以是属性名称或(如果存在)自定义属性 MyAttribute.KeyPropertyC 所示以下。该属性的常见用例是如果键以整数开头,这对 C# 属性名称无效(并且我们无法更改键)。

public class BaseClass
{
    public int BaseClass Id { get; set; } = 0;
}

public class DerivedClassA : BaseClass
{
    public int PropertyA { get; set; }
    public int PropertyB { get; set; }

    [MyAttribute(Key = "404Property")]
    public int PropertyC { get; set; }
}

在代码中,我们需要获取字符串形式的键值。经过一番努力和从其他 SO Answers 中挖掘之后(我没有声称任何级别的泛型专业知识),我们想出了 GetKey()派生中的方法 BaseClass<T>以下。注意 GetCustomAttributeValue<T>()是一个返回属性值的自定义辅助方法(可能有更好的方法,但这超出了这个问题的范围)。

public class BaseClass<T> : BaseClass where T : BaseClass<T>
{
    public string GetKey(Expression<Func<T, object>> property)
    {
        var memberInfo = GetMemberInfo(property);
        return GetAttributeKey(memberInfo) ?? memberInfo?.Name;
    }

    private static MemberInfo GetMemberInfo(Expression<Func<T, object>> property) =>
        (property.Body as MemberExpression ?? ((UnaryExpression)property.Body).Operand as MemberExpression)?.Member;

    private static string GetAttributeKey(MemberInfo member) =>
        member.GetCustomAttributeValue<string>(typeof(MyAttribute), "Key");
}

如果我们从新的 BaseClass<T> 派生类,这个解决方案似乎可行。

    public class DerivedClassA : BaseClass<T> {
        ...
    }

GetKey()现在调用如下:

var derivedClassA = new DerivedClassA();
var propertyCKey = derivedClassA.GetKey(p => p.PropertyC);

我们有一个要求 BaseClass然而,需要保留,我们不希望 BaseClass 的非通用版本和通用版本都很复杂。 .

当我尝试移动时 GetKey()进入非泛型BaseClass , 它不再有 T派生类的类型,它需要查找派生类的属性集。我不想添加重复项 GetKey() s 在每个派生类中。

问题:

有没有办法移动 GetKey()方法(可能重写)到 BaseClass而不是引入新的 BaseClass<T>仅支持GetKey()

其他背景:

我们正在尝试将面向对象/强类型包装在一个数据存储周围,该数据存储只是一个看起来像这样的表:

| PreferenceId | UserId | PreferenceString |

每个派生类代表一个不同的PreferenceId .每个PreferenceString只是一串键/值以自定义的方式“序列化”PreferenceId (所有 PreferenceIds 之间没有可以共享的押韵/原因)。这一切都应该在某个时候重新设计,但我们正在尝试将当前商店包装在某种强类型中,作为过渡的一个步骤。

最佳答案

对我来说,所有这些结构总体上似乎很疯狂而且过于复杂。
考虑重写整个方法而不是更改 GetKey 方法。

一般来说,基类中的 GetKey 会破坏单一职责原则。

如果我必须这样做,我会把这个功能提取到一个静态类中:

public static class CustomKeysHelper
{
    public static string GetKey<T>(Expression<Func<T, object>> property) where T : BaseClass
    {
        var memberInfo = GetMemberInfo(property);
        return GetAttributeKey(memberInfo) ?? memberInfo?.Name;
    }

    private static MemberInfo GetMemberInfo<T>(Expression<Func<T, object>> property) =>
        (property.Body as MemberExpression ?? ((UnaryExpression)property.Body).Operand as MemberExpression)?.Member;

    private static string GetAttributeKey<T>(MemberInfo member) =>
        member.GetCustomAttributeValue<string>(typeof(MyAttribute), "Key");
}

// Usage:
string cKey = CustomKeysHelper.GetKey<DerivedClassA>(dca => dca.PropertyC);

是的,它使每个 GetKey 调用看起来更长,但它分离了这个逻辑并使您的意图清晰。

万一你有对象 BaseClass 的实例并且想从实例中提取属性名称,而不是类型,那么你可以使用扩展方法:

public static class CustomKeysHelper
{
    // ... see above

    public static string GetKey<T>(this T obj, Expression<Func<T, object>> property) where T : BaseClass
    {
        return GetKey<T>(property);
    }
}    

// Now, you can do this:
DerivedClassA derAInstance = ...;
derAInstance.GetKey(dca => dca.PropertyC);

关于c# - 获取派生类属性的属性或名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51540318/

相关文章:

c# - ServicePointManager.FindServicePoint 的用途是什么?

c# - "class A : B<C>"和 "class A<T> : B<T> where T : C"有什么区别?

java - 从 Realm 中获取通用类型的 Realm 对象

c# - EF 代码优先 : Sequence contains more than one matching element

typescript - 返回具有相同属性名称的类型

c# - 在 C# 中概括和聚合 XML 转储的最佳方法是什么?

java - 如何在运行可执行 jar 时查找类

C# 一般设置属性

C#:判断一个类是否已经初始化

c# - asp.net web api - 模型绑定(bind)列表参数