Скажем, у меня есть класс под названием Тест с одним свойством под названием Заголовок с пользовательским атрибутом:
public class Test
{
[DatabaseField("title")]
public string Title { get; set; }
}
И дополнительный метод под названием DbField. Я задаюсь вопросом, если получение пользовательского атрибута от экземпляра объекта даже возможно в c#.
Test t = new Test();
string fieldName = t.Title.DbField();
//fieldName will equal "title", the same name passed into the attribute above
Это может быть сделано?
Вот подход. Метод расширения работает, но это не так просто. Я создаю выражение, а затем получаю настраиваемый атрибут.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
namespace ConsoleApplication1
{
public class DatabaseFieldAttribute : Attribute
{
public string Name { get; set; }
public DatabaseFieldAttribute(string name)
{
this.Name = name;
}
}
public static class MyClassExtensions
{
public static string DbField<T>(this T obj, Expression<Func<T, string>> value)
{
var memberExpression = value.Body as MemberExpression;
var attr = memberExpression.Member.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
return ((DatabaseFieldAttribute)attr[0]).Name;
}
}
class Program
{
static void Main(string[] args)
{
var p = new Program();
Console.WriteLine("DbField = '{0}'", p.DbField(v => v.Title));
}
[DatabaseField("title")]
public string Title { get; set; }
}
}
Это так, но в конечном итоге это будет окольный путь, поскольку вы получите экземпляр Type
после вызова GetType
в вашем экземпляре, который предоставляет свойство, а затем продолжите работу над что (чаще всего).
В этом конкретном случае ваш метод расширения не сможет получить информацию об атрибуте, потому что все, что вы ему передаете, является строкой.
В конечном итоге вам нужно что-то, чтобы получить PropertyInfo
для свойства. Другие ответы относятся к типу
, чего им не хватает, это не единственный способ получить необходимую информацию об атрибутах в PropertyInfo
.
Вы можете сделать это, передав экземпляр Type
со строкой, предположительно с именем свойства, чтобы вы могли вызвать GetProperty
для Type
.
Другой способ сделать это, начиная с C # 3.0, заключался в использовании метода, который принимает Expression
, а затем использует части Expression
для получения ] PropertyInfo
. В этом случае вы должны взять Expression
или что-то, где TResult
является строкой.
Получив PropertyInfo
, вы можете вызвать для него GetCustomAttributes
и найти свой атрибут.
Преимущество подхода выражений состоит в том, что Expression
происходит от LambdaExpression
, которую можно вызвать Compile
, а затем вызвать для получения фактическая стоимость, если она вам нужна.
Поскольку в C++ строковые литералы (например, «Hello»
не относятся к типу std:: string
. Это простые массивы символов или последовательности в стиле Си.
Поэтому для строки const std:: string message = «Hello» +, «world» + exclam;
компилятор должен работать со следующими типами:
const std:: строковое сообщение = const char [6] + const char [8] + std:: Последовательность;
и учитывая ассоциативность +
, необходимо выполнить следующие операции:
const std:: строковое сообщение = ((const char [6] + const char [8]) + std:: последовательность);
То есть сначала должно быть вычислено самое левое сложение, а результат передан самому правому сложению.
Поэтому компилятор пытается вычислить const char [6] + const char [8]
.
Для массивов не определено добавление. Массивы неявно преобразуются в указатели, но это не помогает компилятору. Это означает, что в конечном итоге появится const char * + const char *
, и для указателей также не определено добавление.
На данном этапе не известно, что результат должен быть преобразован в std:: Последовательностью
.
Однако во втором примере
const std::string hello = "Hello";
const std::string message = hello + ", world" + "!";
это работает, поскольку операции, которые будет видеть компилятор, std:: Последовательности + const char [8] + const char [2]
. Здесь первое сложение может быть преобразовано в std:: string + const char *
, и здесь оператор сложения определен и возвращает std:: string
. Так что компилятор успешно вычислил первое сложение, и так как результатом была последовательность, второе сложение выглядит так: std:: Последовательности + const char [2]
, и как и раньше, это невозможно, но массив можно преобразовать в указатель, и тогда компилятор сможет найти оператор сложения, который работает, снова приводя к std:: Последовательности
.
От прочтения руководства здесь: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html Я думаю, что вам нужно несколько вызовов для CURL_SETOPT, первый из которых - URL, который вы хотите обработать, второй - что-то вроде:
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, function_ptr);
Где function_ptr соответствует этой подписи:
size_t function( void *ptr, size_t size, size_t nmemb, void *stream)
Что происходит здесь, так это то, что вы обозначаете функцию обратного вызова, которую libcurl будет вызывать, когда у него есть некоторые выходные данные для записи из любой передачи вы Можно получить его для автоматической записи в файл или передать его указатель на функцию, которая будет обрабатывать сам вывод. С помощью этой функции можно собрать различные выходные последовательности в единое целое и затем использовать их в программе.
Я не уверен, какие другие параметры вам, возможно, придется установить/что еще влияет на то, как вы хотите, чтобы ваше приложение повело себя, поэтому хорошо посмотрите на эту страницу.
-121--832629-Нет, это невозможно. Причина этого в том, что это значение, а не само свойство, которое будет отправлено в любой пользовательский метод расширения, который будет извлекать эту информацию. Как только вы попадете в этот метод расширения,нет надежного способа отследить саму собственность.
Возможно для значений перечисления , но что касается свойств POCO, то они не идти на работу.
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Console.WriteLine(t.FieldName("Title").FieldName<DatabaseFieldAttribute>());
Console.WriteLine(t.FieldName("Title").FieldIsPrimaryKey<DatabaseFieldAttribute>());
}
}
public class Test
{
[DatabaseField("titlezzz", true)]
public string Title
{
get;
set;
}
}
public class BaseDatabaseFieldAttribute : Attribute
{
private readonly string _name;
public string Name { get { return _name; } }
public BaseDatabaseFieldAttribute(string name)
{
_name = name;
}
}
public class DatabaseFieldAttribute : BaseDatabaseFieldAttribute
{
private readonly bool _isPrimaryKey;
public bool IsPrimaryKey { get { return _isPrimaryKey; } }
public DatabaseFieldAttribute(string name, bool isPrimaryKey): base(name)
{
_isPrimaryKey = isPrimaryKey;
}
}
public static class Helper
{
public static PropertyInfo FieldName(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName);
}
public static string FieldName<T>(this PropertyInfo property) where T: BaseDatabaseFieldAttribute
{
object[] os = property.GetCustomAttributes(typeof(T), false);
if (os != null && os.Length >= 1)
return (os[0] as T).Name;
else
return "N/A";
}
public static bool? FieldIsPrimaryKey<T>(this PropertyInfo property) where T : DatabaseFieldAttribute
{
object[] os = property.GetCustomAttributes(typeof(T), false);
if (os != null && os.Length >= 1)
return (os[0] as T).IsPrimaryKey;
else
return null;
}
}
}
Как уже было отмечено, это невозможно с синтаксисом, описанным оригинальным постером, потому что вы не можете получить ссылку на PropertyInfo внутри метода расширения. Как насчет чего-то вроде этого:
// Extension method
public static string GetDbField(this object obj, string propertyName)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName);
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(DatabaseFieldAttribute), true);
if (dbFieldAtts != null && dbFieldAtts.Length > 0)
{
return ((DatabaseFieldAttribute)dbFieldAtts[0]).Name;
}
return "UNDEFINED";
}
Тогда вы могли бы получить информацию просто:
Test t = new Test();
string dbField = t.GetDbField("Title");
Чтобы получить значение атрибута, вам нужен тип, к которому этот атрибут применяется. Ваш метод расширения получает только строковое значение (значение Title), поэтому вы не сможете получить фактический экземпляр, из которого пришла строка, и поэтому вы не можете получить исходный тип, которому принадлежит свойство Title. Это сделает невозможным получение значения атрибута из вашего метода расширения.