C # получить метод расширения пользовательского атрибута

#c# #mongodb #json.net

#c# #mongodb #json.net

Вопрос:

может кто-нибудь помочь мне создать метод расширения для пользовательских атрибутов для newtonsoft.json и mongodb?

Допустим, у меня есть следующий класс:

 public class Foo
{
    [BsonElement("MyCustomDbName")]
    [JsonProperty("MyCustomJsonName")]
    public string Name { get; set; }
}
 

Как создать метод расширения, чтобы получить следующее:

 var myFoo = new Foo(){Name=""};
var mongoDbElementName = myFoo.Name.GetMongoDbElementName(); // should return 'MyCustomDbName'
var jsonPropertyName = myFoo.Name.GetJsonPropertyName(); // should return 'MyCustomJsonName'
 

или непосредственно с самим классом:

 var mongoDbElementName = Foo.Name.GetMongoDbElementName(); // should return 'MyCustomDbName'
var jsonPropertyName = Foo.Name.GetJsonPropertyName(); // should return 'MyCustomJsonName'
 

Я пробовал подобные вещи:

 public static string GetMongoDbElementName(this Type modelType, PropertyInfo property)
{
    return (modelType.GetProperty(nameof(property)) ?? throw new InvalidOperationException()).GetCustomAttribute<BsonElementAttribute>()?.ElementName;
}
 

Но есть ли способ сделать это без параметра?

Спасибо заранее

Ответ №1:

Вы не можете сделать это непосредственно в свойстве; вам нужно будет применить метод расширения к классу и использовать выражение для выбора свойства:

 public static string GetMongoDbElementName<T>(
    this T obj,
    Expression<Func<T, object>> propertySelector)
{
    var memberExpression = propertySelector.Body as MemberExpression;
    var memberName = memberExpression?.Member.Name
        ?? throw new InvalidOperationException();

    var bsonAttribute = obj
        .GetType()
        .GetProperty(memberName)
        .GetCustomAttribute<BsonElementAttribute>();

    return bsonAttribute?.ElementName;
}
 

Использование:

 var mongoDbElementName = myFoo.GetMongoDbElementName(x => x.Name);
 

Вы также можете захотеть обновить код для защиты от выбора других элементов (например, метода), что можно сделать следующим образом:

 var property = obj
    .GetType()
    .GetProperty(memberName)
    ?? throw new InvalidOperationException($"{memberName} is not a property");
 
var bsonAttribute = property
    .GetCustomAttribute<BsonElementAttribute>();
 

Комментарии:

1. СПАСИБО, хорошее решение!!!

Ответ №2:

Вы можете получить атрибут и его значение, используя отражение:

 public static string GetBsonElementName(this Foo foo)
{
    var bsonElementAttribute =
        typeof(Foo)
        .GetProperty(nameof(Foo.Name))
        .GetCustomAttribute<BsonElementAttribute>();

    return bsonElementAttribute.ElementName;
}

public static string GetJsonPropertyName(this Foo foo)
{
    var jsonPropertyAttribute =
        typeof(Foo)
        .GetProperty(nameof(Foo.Name))
        .GetCustomAttribute<JsonPropertyAttribute>();

    return jsonPropertyAttribute.PropertyName;
}
 

Вы используете его следующим образом:

 var foo = new Foo();
var bsonElementName = foo.GetBsonElementName();
var jsonPropertyName = foo.GetJsonPropertyName();
 

Комментарии:

1. Это вряд ли будет полезно, учитывая, что оно жестко Foo.Name запрограммировано.

2. Кроме того, что такое BsonName ?