2

I'm not quite sure the correct way of asking this question, so I'm just going to go for it.

I am looking for the cleanest way of passing in "parameter sets" into a Method. For instance:

Dictionary<string, string> Parameters = new Dictionary<string, string>();
Parameters.Add("UserID", "12");
Parameters.Add("SiteID", "43");

CreateLog("Hello World!", Parameters);

public void CreateLog(string Message, Dictionary<string, string> Parameters)
{
    ...
}

However, I would like to do this in a much cleaner way and I'm sure there is some method of doing it that I can't think of. I could make a custom object that takes a string and an object, for instance:

public void CreateLog(string Message, params LogParameter[] Parameters)
{
    ...
}

Then I could create a new Log Parameter for each Parameter and pass it in, but I would like to be a bit more concise than that and avoid having to create all those new objects for something that (I think) should be simpler.

One possible solution is to do something like this:

CreateLog("Hello World!", new { UserID = 12, SiteID = 43 });

public void CreateLog(string Message, object Parameters)
{
    ...
}

This is similar to how C# ASP.NET creates URL variables/how DevExpress creates callbacks for their controls. But how do they get the values out of the object in the method?

Any thoughts?

9
  • 1
    new { UserID = 12, SiteID = 43 } is still creating an object, it's just the type happens to be anonymous. You will probably end up doing more work in CreateLog, though, trying to access its properties. Commented Dec 16, 2015 at 18:20
  • 2
    What you have is already a clean way. Commented Dec 16, 2015 at 18:21
  • 1
    Why is the first option "not clean"? Because of the strings for the names? Why are they strings in the first place, do you want to log arbitrary key-value pairs? As for your latest suggestion: have you heard of reflection? Commented Dec 16, 2015 at 18:22
  • 1
    To answer your question "How to get value out of the object in Method?". This will be done via Reflection Parameters.GetType().GetAllProperties() and get the value and name of each property with a foreach loop. Commented Dec 16, 2015 at 18:28
  • @BACON - I realize that I am still creating an object with new { ... } but I think it is nicer because creating a new object for each and every parameters just adds alot more repetitive code (i.e. new LogParameter("UserID", "12"), new LogParameters("SiteID", "423")) instead of new { UserID = 12, SiteID = 423 }. And I don't mind having a bit of logic in CreateLog if necessary - since it will be in one place but called from hundreds. Commented Dec 16, 2015 at 18:42

2 Answers 2

1

Three options as I see it:

  1. Use a dictionary as you've already suggested.

  2. Create a class that functions as a DTO and pass that:

    public class LogParameters
    {
        public int UserId { get; set; }
        public int SiteId { get; set; }
    }
    
    public void CreateLog(string message, LogParameters parameters)
    
  3. Use an anonymous object, an approach you've also suggested. In your method, you'll have to rely on reflection to transform the object into something you can actually utilize.

    Microsoft provides a way to do this via HtmlHelper.AnonymousObjectToHtmlAttributes, but so you don't need a dependency on the System.Web.Mvc namespace, the source for that method is as follows:

    public static IDictionary<string, object> AnonymousObjectToHtmlAttributes(object htmlAttributes)
    {
        Dictionary<string, object> result;
        var valuesAsDictionary = htmlAttributes as IDictionary<string, object>;
        if (valuesAsDictionary != null)
        {
            result = new Dictionary<string, object>(valuesAsDictionary, StringComparer.OrdinalIgnoreCase);
        }
        else
        {
            result = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
    
            if (htmlAttributes != null)
            {
                foreach (var prop in htmlAttributes.GetType().GetRuntimeProperties())
                {
                    var value = prop.GetValue(htmlAttributes);
                    result.Add(prop.Name, value);
                }
            }
        }
    
        return result;
    }
    

    That should give you the inspiration you need to adapt it for your own code.

Personally, I generally go with approach 1 or 2 in these scenarios. The syntactic sugar of using an anonymous object is tempting, but if your method depends on the proper params being provided, it can be a crap shoot. Honestly, the dictionary approach suffers in this way as well, but at least there, you're not dealing with reflection.

Technically speaking, methods should be self-documenting, which means you should be passing in either individual named params or a class instance. That way, you have the assurance that what you expect to be available to your method is there, and the end-user of the method can see at a glance what's required to satisfy it. Neither a dictionary nor an anonymous object gives you either of these, and if you notice, the only times Microsoft uses anonymous objects as a param, the contents are completely optional, such as htmlAttributes in a helper. If certain keys don't exist, then it's no big deal, since it's all optional anyways.

Sign up to request clarification or add additional context in comments.

3 Comments

That's basically my situation - I want to be able to pass in ad hoc parameters to a logging class so that it can record information about what is going on when the log occurred - it is also already an MVC project so I might just use that method - thank you very much!
Just a note about that method. The code I posted is the latest in Github and roughly corresponds with MVC6. In previous versions of MVC, RouteValueDictionary is returned rather than IDictionary. Might not have any bearing either way as they both perform the same for the most part, but something to be aware of.
Do you happen to know the difference between .GetProperties() and .GetRuntimeProperties()?
1

Here's the catch, how you can use reflection to get properties out of a Anonymous type passed as object to a method.

    public void CreateLog(object parameters)
    {
        foreach(var property in parameters.GetType().GetProperties())
        {
            WriteLog(string.Format("{0} - {1}",property.Name, property.GetValue(parameters)));
        }
    }

Usage:

CreateLog(new {SiteID = 1, UserId = 2});

4 Comments

I have heard that calls to reflection can be pretty slow - my application is not very performance sensitive and this will only be used when a log event happens (which is not constantly). Off the top of your head, should I be worried about performance here or is the GetProperties() command pretty quick?
Can't give you number or exact statement but I'm sure It's almost negligible as compared to the log operation itself :)
Reflection is slow, but we're talking milliseconds, not minutes or even seconds. The issue is that even milliseconds add up over time. The caution is against making heavy use of reflection, limited and minor usage is probably not going to affect your app either way. Even Entity Framework which relies on reflection for most of its functionality, manages to be relatively quick about it. Although, it is still one of the slowest .NET ORMs, so take what you will from that.
@vendettamit that's what I figured - especially since the log ships off the message to Azure Insights - the reflection will probably be negligible -

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.