Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.7k views
in Technique[技术] by (71.8m points)

json - C# - Better way to pass in <key, value> pairs to create JProperty objects

My log4net object looks something like this (since I want to log my set as a json object)

_log.Debug(new JObject(new JProperty("Prop1", "Val1"),
                       new JProperty("Prop2", "Val2")).ToString());       

For better code readability and easy adding of additional properties, I'd like to do something like this

Utility.WriteLog({"Prop1", "Val1"}, 
                 {"Prop2", "Val2"});

I am not sure how the WriteLog() method would look like other than that it should have a params argument considering that there will be a variable number of property/value pairs that need to be logged.

I have considered a dictionary (see below) and the WriteLog function would create a JsonObject with the property/value keys from the dictionary:

Utility.WriteLog(new Dictionary<string, string>()
                        {
                            {"Prop1", "Val1"}, 
                            {"Prop2", "Val2" }
                        });

Is this the best approach, or is there a more succinct alternative?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you are using c# 7.0 or later, you could use the simplified tuple syntax to pass in a params array of name/value tuples for formatting via serialization and subsequent logging.

Since you have tagged your question , you could define extension methods on ILog like so:

public static partial class LogExtensions
{
    public static void DebugProperties(this ILog log, params (string Name, object Value) [] parameters)
        // TODO: handle duplicate Name keys in some graceful manner.
        => log.Debug(JsonConvert.SerializeObject(parameters.ToDictionary(p => p.Name, p => p.Value), Formatting.Indented));
    
    public static void InfoProperties(this ILog log, params (string Name, object Value) [] parameters)
        => log.Info(JsonConvert.SerializeObject(parameters.ToDictionary(p => p.Name, p => p.Value), Formatting.Indented));
}

And then call them like:

log.DebugProperties(("Prop1", "Val1"), ("Prop2", "Val2"));
log.InfoProperties(("Prop3", new SomeClass { SomeValue = "hello" }));

And get the output:

2021-01-21 21:12:36,215 DEBUG: {
  "Prop1": "Val1",
  "Prop2": "Val2"
}
2021-01-21 21:12:36,230 INFO : {
  "Prop3": {
    "SomeValue": "hello"
  }
}

If you are using c# 9.0 or later, you could also add a logging method taking a Dictionary<string, object> and, when calling the method, use the abbreviated new () syntax which omits the type when already known:

public static partial class LogExtensions
{
    public static void DebugDictionary(this ILog log, Dictionary<string, object> parameters)
        => log.Debug(JsonConvert.SerializeObject(parameters, Formatting.Indented));
}

And then later:

log.DebugDictionary(new () { {"Prop1", "Val1"}, {"Prop2", "Val2" } } );

Of course, if you prefer you could wrap your ILog log in a Utility class with methods whose inputs are like those of the extension methods above, but it isn't necessary if you use extension methods.

Demo fiddle here.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...