获取派生类属性的属性或名称

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


派生类上的每个属性都将映射到存储中的一个键。属性表示的键是字符串值,它们是属性名称或(如果存在)自定义属性MyAttribute.Key,PropertyC如下所示。属性的常见用例是如果键以整数开头,这对于 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 答案中进行了一些摔跤和挖掘之后(我不声称对泛型具有任何专业水平),我们想出了下面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()进入 non-generic 时BaseClass,它不再具有T派生类的类型,它需要在派生类上查找属性集。我不想GetKey()在每个派生类中添加重复的s。


题:


有没有办法将GetKey()方法(可能重写它)移入BaseClass而不是引入新的BaseClass<T>仅用于支持GetKey()?


附加背景:


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


| PreferenceId | UserId | PreferenceString |

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


婷婷同学_
浏览 218回答 1
1回答

慕丝7291255

对我而言,所有这些结构总体上似乎很疯狂且过于复杂。考虑重写整个方法而不是改变GetKey方法。一般来说,GetKey在你的基类中打破单一职责原则。如果我必须这样做,我会把这个功能提取到一个静态类中:public static class CustomKeysHelper{&nbsp; &nbsp; public static string GetKey<T>(Expression<Func<T, object>> property) where T : BaseClass&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var memberInfo = GetMemberInfo(property);&nbsp; &nbsp; &nbsp; &nbsp; return GetAttributeKey(memberInfo) ?? memberInfo?.Name;&nbsp; &nbsp; }&nbsp; &nbsp; private static MemberInfo GetMemberInfo<T>(Expression<Func<T, object>> property) =>&nbsp; &nbsp; &nbsp; &nbsp; (property.Body as MemberExpression ?? ((UnaryExpression)property.Body).Operand as MemberExpression)?.Member;&nbsp; &nbsp; private static string GetAttributeKey<T>(MemberInfo member) =>&nbsp; &nbsp; &nbsp; &nbsp; member.GetCustomAttributeValue<string>(typeof(MyAttribute), "Key");}// Usage:string cKey = CustomKeysHelper.GetKey<DerivedClassA>(dca => dca.PropertyC);是的,它让每次GetKey调用看起来更长,但它分离了这个逻辑并使你的意图清晰。万一您有对象的实例BaseClass并想从实例中提取属性名称,而不是类型,那么您可以使用扩展方法:public static class CustomKeysHelper{&nbsp; &nbsp; // ... see above&nbsp; &nbsp; public static string GetKey<T>(this T obj, Expression<Func<T, object>> property) where T : BaseClass&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return GetKey<T>(property);&nbsp; &nbsp; }}&nbsp; &nbsp;&nbsp;// Now, you can do this:DerivedClassA derAInstance = ...;derAInstance.GetKey(dca => dca.PropertyC);
打开App,查看更多内容
随时随地看视频慕课网APP