Использование Reflection.Emit для копирования пользовательского атрибута в другой метод - PullRequest
4 голосов
/ 02 марта 2010

Я пытаюсь создать новый набор интерфейсов wcf на основе существующих интерфейсов. Я использую пространство имен Reflection.Emit для достижения этой цели. Моя проблема заключается в том, как скопировать старые пользовательские атрибуты из одного метода в новый метод. Каждый пример SetCustomAttributes (), который я видел, требует предварительного знания типа атрибута. Мне нужно обнаружить тип атрибута во время выполнения. Какие-нибудь мысли?

Ответы [ 4 ]

5 голосов
/ 12 октября 2010

Ответ, который вы (frjames) опубликовали, близок, но не учитывает инициализаторы свойств, такие как ...

[ServiceBehavior(Name="ServiceName")]

Однако идея преобразования CustomAttributeData в CustomAttributeBuilder для использования в Reflection.EmitПравильно.

Я закончил тем, что сделал это для проекта с открытым исходным кодом (Autofac) и придумал этот метод расширения:

public static CustomAttributeBuilder ToAttributeBuilder(this CustomAttributeData data)
{
  if (data == null)
  {
    throw new ArgumentNullException("data");
  }

  var constructorArguments = new List<object>();
  foreach (var ctorArg in data.ConstructorArguments)
  {
    constructorArguments.Add(ctorArg.Value);
  }

  var propertyArguments = new List<PropertyInfo>();
  var propertyArgumentValues = new List<object>();
  var fieldArguments = new List<FieldInfo>();
  var fieldArgumentValues = new List<object>();
  foreach (var namedArg in data.NamedArguments)
  {
    var fi = namedArg.MemberInfo as FieldInfo;
    var pi = namedArg.MemberInfo as PropertyInfo;

    if (fi != null)
    {
      fieldArguments.Add(fi);
      fieldArgumentValues.Add(namedArg.TypedValue.Value);
    }
    else if (pi != null)
    {
      propertyArguments.Add(pi);
      propertyArgumentValues.Add(namedArg.TypedValue.Value);
    }
  }
  return new CustomAttributeBuilder(
    data.Constructor,
    constructorArguments.ToArray(),
    propertyArguments.ToArray(),
    propertyArgumentValues.ToArray(),
    fieldArguments.ToArray(),
    fieldArgumentValues.ToArray());
}

Это объясняет все способыинициализировать атрибут.

2 голосов
/ 03 марта 2010

Вот ответ, который я пришел после еще одного исследования.

CustomAttributeBuilder ct = AddAttributesToMemberInfo(methodInfo);
if (ct != null)
{
    methodBuilder.SetCustomAttribute(ct);
}

CustomAttributeBuilder AddAttributesToMemberInfo(MemberInfo oldMember)
{
    CustomAttributeBuilder ct = null;
    IList<CustomAttributeData> customMethodAttributes = CustomAttributeData.GetCustomAttributes(oldMember);
    foreach (CustomAttributeData att in customMethodAttributes)
    {
        List<object> namedFieldValues = new List<object>();
        List<FieldInfo> fields = new List<FieldInfo>();
        List<object> constructorArguments = new List<object>();
        foreach (CustomAttributeTypedArgument cata in att.ConstructorArguments)
        {
            constructorArguments.Add(cata.Value);
        }
        if (att.NamedArguments.Count > 0)
        {
            FieldInfo[] possibleFields = att.GetType().GetFields();

            foreach (CustomAttributeNamedArgument cana in att.NamedArguments)
            {
                for (int x = 0; x < possibleFields.Length; x++)
                {
                    if (possibleFields[x].Name.CompareTo(cana.MemberInfo.Name) == 0)
                    {
                        fields.Add(possibleFields[x]);
                        namedFieldValues.Add(cana.TypedValue.Value);
                    }
                }


            }
        }

        if (namedFieldValues.Count > 0)
        {
            ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray(), fields.ToArray(), namedFieldValues.ToArray());
        }
        else
        {
            ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray());
        }


    }
    return ct;
}
1 голос
/ 30 мая 2017

Код от Travis Illig нуждается в корректировке, как показано ниже, для работы с .Net Core:

foreach (var namedArg in data.NamedArguments)
{
  string argName = namedArg.MemberName;
  var fi = data.AttributeType.GetField(argName);
  var pi = data.AttributeType.GetProperty(argName);
0 голосов
/ 02 марта 2010

попробуйте это:

MethodInfo mi;
//...
object[] custAttribs = mi.GetCustomAttributes(false);
foreach (object attrib in custAttribs)
   attrib.GetType();

Я полагаю, у вас есть MethodInfo для ваших методов

...