【问题标题】:Is it possible to get VALUE from nameof(VALUE)?是否可以从 nameof(VALUE) 中获取 VALUE?
【发布时间】:2019-04-12 00:24:24
【问题描述】:

我正在记录异常。现在我有能力用任何参数抛出异常并将它们提供给 log 方法。我想在日志消息中显示每个参数的名称、类型和值。类型和值没有问题,但我无法获取变量的名称。我不想让参数的数量翻倍,在抛出时为每个参数添加nameof(Value)。

这就是我使用不同参数的方式:

        throw new TestException(new object[]{ var0,
                                              var1,
                                              var2,
                                              var3,
                                              var4 });

这就是我不想扔的方式:

        throw new TestException(new object[]{ var0, nameof(var0)
                                              var1, nameof(var1)
                                              var2, nameof(var2)
                                              var3, nameof(var3)
                                              var4, nameof(var4) });

这些是我对在对象中包装数据的想法:

public class ArgWrapper
{
    public ArgWrapper()
    {

    }

    public string Type { get; set; }
    public string Name { get; set; }
    public object Value { get; set; }
}

因此,我希望收集具有此类字段的对象,因此我将记录有关每个参数的信息,例如:{ Type: "type", Name: "name", Value: "value" }

【问题讨论】:

标签: c#


【解决方案1】:

你需要使用GetProperties(),该方法返回所有属性

object example  = new {si= DateTime.Now, no= "no"}; //object example

var typevar  = example.GetType().GetProperties(); //get all te props
//lets loop all the props because it GetProperties() return all props
foreach(var i in typevar){
     //if is DateTime well write the name of prop with i.Name 
     Console.WriteLine("The prop {0} is date time", i.Name);

}

【讨论】:

  • @JorgeFelixCzarez 这很好,但我现在如何获得价值?)))
  • 您可以将i.Name/ property.Name 保存在var中,或者在循环中列出或添加,使用最适合您的方式
【解决方案2】:

向 ArgWrapper 类添加一个方法,该方法可以从参数的表达式中检索您需要的信息。像这样:

public class ArgWrapper
{
    public static ArgWrapper Create<T>(Expression<Func<T>> expression)
    {
        T valueAsT = expression.Compile()();
        string value = Convert.ToString(valueAsT, CultureInfo.InvariantCulture);

        // Get type name
        string type = valueAsT?.GetType().FullName ?? "null";

        string name = "";

        // Get name by traversing memberexpressions from right to left
        MemberExpression memberExpression = expression.Body as MemberExpression;
        Expression traverseExpression = expression.Body;
        while (traverseExpression != null && traverseExpression is MemberExpression)
        {
            memberExpression = traverseExpression as MemberExpression;
            name = memberExpression.Member.Name + "." + name;
            traverseExpression = memberExpression.Expression;
        }

        // If the last memberexpression has no expression, this is a global class name, we want to include
        if (traverseExpression == null && memberExpression != null)
        {
            name = memberExpression.Member.DeclaringType.Name + "." + name;
        }

        var argWrapper = new ArgWrapper();
        argWrapper.Name = name;
        argWrapper.Type = type;
        argWrapper.Value = value;

        return argWrapper;
    }

    public string Type { get; set; }
    public string Name { get; set; }
    public object Value { get; set; }
}

如果这是你的异常类

public class TestException : Exception
{
    private List<ArgWrapper> parameters = new List<ArgWrapper>();
    public IEnumerable<ArgWrapper> Parameters => parameters;

    public TestException(params ArgWrapper[] passedParameters)
    {
        parameters.AddRange(passedParameters);
    }
}

然后你可以像这样使用它

private void button1_Click(object sender, EventArgs e)
{
    string s = "Hello World";
    double pi = Math.PI;
    string nullString = null;

    var exception = new TestException(
        ArgWrapper.Create(() => 42),
        ArgWrapper.Create(() => s),
        ArgWrapper.Create(() => s.Length),
        ArgWrapper.Create(() => pi),
        ArgWrapper.Create(() => button1.Text),
        ArgWrapper.Create(() => Application.CurrentCulture.Calendar.AlgorithmType),
        ArgWrapper.Create(() => DateTime.Now),
        ArgWrapper.Create(() => nullString)
        );


    foreach(var param in exception.Parameters)
    {
        Console.WriteLine($"{param.Name} - {param.Type} - {param.Value}");
    }

}

这将产生这个输出:

- System.Int32 - 42 s。 - System.String - 你好世界 s.长度。 - System.Int32 - 11 圆周率。 - System.Double - 3.14159265358979 按钮1.文本。 - System.String - 按钮1 Application.CurrentCulture.Calendar.AlgorithmType。 - System.Globalization.CalendarAlgorithmType - SolarCalendar 日期时间。现在。 - System.DateTime - 04/11/2019 18:23:42 空字符串。 - 无效的 -

【讨论】:

  • 谢谢你,伙计。这正是我所需要的。那是如此美丽和强大))Day tebe Bog zdorov'ya))@NineBerry
【解决方案3】:

第一部分是正确的。 您需要将属性定义为公共的,并且您需要知道包含属性的对象!

public Object TestProperty { get; set; } = "test";

private void GetFromName()
{
   var properties = this.GetType().GetProperties();
   var foundProperty = properties.ToList().Find(property => property.Name == /* nameof(x) string */);

   var test = foundProperty.GetValue(/* object containing the property */);
}

【讨论】:

    猜你喜欢
    • 2010-11-16
    • 2012-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-12
    • 1970-01-01
    • 2019-03-28
    相关资源
    最近更新 更多