Разрешение названия параметра во времени выполнения [дубликат]

Трудно сказать из вашего кода, какова ваша цель, может быть, вы просто экспериментируете с Enum, но, может быть, Map.values/1 - лучший выбор здесь?

iex(1)> val_map = %{"pri" => %{"tit" => "name1"}, "sec" => %{"tat" => "name2"}}
%{"pri" => %{"tit" => "name1"}, "sec" => %{"tat" => "name2"}}
iex(2)> Map.values(val_map)
[%{"tit" => "name1"}, %{"tat" => "name2"}]

[116 ] Отвечая на разъяснения в комментариях, вы можете сделать это так:

iex(1)> val_map = %{"pri" => %{"tit" => "name1"}, "sec" => %{"tit" => "name2"}}
%{"pri" => %{"tit" => "name1"}, "sec" => %{"tit" => "name2"}}
iex(2)> Enum.map(val_map, fn {k, %{"tit" => v}} -> %{k => v} end)
[%{"pri" => "name1"}, %{"sec" => "name2"}]

20
задан Community 23 May 2017 в 12:14
поделиться

4 ответа

Односторонний:

static void Main(string[] args)
{
  Console.WriteLine("Name is '{0}'", GetName(new {args}));
  Console.ReadLine();
}

Этот код также требует вспомогательной функции:

static string GetName<T>(T item) where T : class
{
  var properties = typeof(T).GetProperties();
  Enforce.That(properties.Length == 1);
  return properties[0].Name;
}

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

Подробности здесь: http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html

26
ответ дан 29 November 2019 в 23:20
поделиться

Эту информацию можно получить с помощью АОП. Вы можете определить перехват, который вызывается перед выполнением метода, и генерировать исключение там. Это также решает проблему, заключающуюся в том, что проверка нуля является сквозной проблемой.

PostSharp - хорошая простая реализация АОП.

Вот как будет выглядеть ваш код (не тестировал, но он должен вас очень близко)

[AttributeUsage(AttributeTargets.Parameter)]
public class CanBeNullAttribute : Attribute
{
    private readonly bool canBeNull;

    public CanBeNullAttribute()
        : this(true)
    {
    }

    public CanBeNullAttribute(bool canBeNull)
    {
        this.canBeNull = canBeNull;
    }

    public bool AllowNull
    {
        get { return canBeNull; }
    }
}

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class EnforceNullConstraintAttribute : OnMethodInvocationAspect
{
    public override void OnInvocation(MethodInvocationEventArgs eventArgs)
    {
        object[] arguments = eventArgs.GetArgumentArray();
        ParameterInfo[] parameters = eventArgs.Delegate.Method.GetParameters();

        for (int i = 0; i < arguments.Length; i++)
        {
            if (arguments[i] != null) continue;

            foreach (CanBeNullAttribute attribute in parameters[i].GetCustomAttributes(typeof(CanBeNullAttribute), true))
            {
                if (!attribute.AllowNull) throw new ArgumentNullException(parameters[i].Name);
            }
        }

        base.OnInvocation(eventArgs);
    }
}

Теперь вы можете изменить свой метод:

[EnforceNullConstraint]
public void Woof([CanBeNull(false)] object resource)
{
    // no need to check for null, PostSharp will weave it at compile time

    // execute logic assured that "resource" is not null
}
3
ответ дан 29 November 2019 в 23:20
поделиться

Краткий ответ: Нет, нет. (Это достаточно кратко?;)

(РЕДАКТИРОВАТЬ: ответ Джастина, вероятно, имеет значение. Он оставляет неприятный привкус во рту, но он выполняет цель «нет необходимости помещать имя параметра в строку». Я не делаю этого » Не думаю, что я действительно посчитал бы АОП, поскольку это действительно переход к совершенно другому подходу, а не к ответу на исходный вопрос о получении имени параметра из метода.)

Более длинный ответ: есть способ узнать все параметры метода, но я не думаю, что это полезно в данном случае.

Вот пример, который отображает имена параметров из пары методов:

using System;
using System.Reflection;

class Test
{
    static void Main()
    {
        Foo(null);
        Bar(null);
    }

    static void Foo(object resource)
    {
        PrintParameters(MethodBase.GetCurrentMethod());
    }

    static void Bar(object other)
    {
        PrintParameters(MethodBase.GetCurrentMethod());
    }

    static void PrintParameters(MethodBase method)
    {
        Console.WriteLine("{0}:", method.Name);
        foreach (ParameterInfo parameter in method.GetParameters())
        {
            Console.WriteLine(" {0} {1}",
                              parameter.ParameterType,
                              parameter.Name);
        }
    }
}

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

public void Woof(object resource)
{
    if (resource == null)
    {
        throw new ArgumentNullException(infoof(resource));
    }

    // ..
}

, где мифический оператор infoof вернет ParameterInfo . К сожалению, этого не существует.

15
ответ дан 29 November 2019 в 23:20
поделиться

Я занимался той же проблемой. Есть несколько способов получить имя параметра, но самый эффективный - погрузиться в IL. Вы можете увидеть пример моей реализации в моем сообщении в блоге по этой самой проблеме Устранение боли при проверке параметров .

Единственное предостережение в отношении этого подхода заключается в том, что вам необходимо передать имя параметра в качестве делегата, но это небольшая плата за более чистый код:

public void SomeMethod(string value)
{
    Validate.Argument(() => value).IsNotNull().IsNotEmpty();
}

Что несколько чище и понятнее, чем:

public void SomeMethod(string value)
{
    if (value == null)
    {
        throw new ArgumentNullException("value");
    }
    if (value == string.Empty)
    {
        throw new ArgumentException("Value cannot be an empty string.", "value");
    }
}

Подход со статическим методом позволил мне объединить несколько методов в единый свободный интерфейс. Первоначально возвращается объект Argument, который допускает только базовый нулевой тест, который возвращает объект ReferenceArgument, который затем может иметь дополнительную проверку. Если тестируемый объект относится к типу значений, доступны различные тесты.

API позволяет выполнять ряд общих тестов, но было бы трудно охватить все возможные тесты, поэтому для обеспечения гибкости общий метод тестирования позволяет предоставлять выражение или функцию, а в первом случае выражение может фактически использоваться как сообщение об ошибке.

Мой пример охватывает лишь некоторые из основ, но вы можете легко расширить интерфейс, чтобы проверить диапазоны и выбросить исключения ArgumentOutOfRangeExceptions или тестовые объекты, унаследованные от определенного базового класса, или реализовать интерфейс. Есть несколько подобных реализаций, но я еще не видел ни одной, которая бы получила имя параметра.

5
ответ дан 29 November 2019 в 23:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: