简体   繁体   中英

.NET Dictionary vs Class Properties

Coming from a javascript background, collections like dictionaries are often implemented as objects because their properties can be referenced by association:

// js example
var myDict = {
  key1 : "value1",
  key2 : "value2"
};

myDict.key1;    // "value1"
myDict["key1"]; // "value1"

However, in C# it seems we have to choose between static singleton classes and generic dictionaries for each effect. While I like that classes are strongly typed and give intellisense support, Dictionary methods offer flexibility I'm hesitant to give up. Are there performance considerations so great in C# that I should choose one over the other?

In fact, a class would be several orders of magnitude faster than a Dictionary . If you feel it's more convenient, that's even better :) So if you're able to make classes for it, do so. If the objects you represent really should be classes (ie are fundamentally objects and not key/value pairs) then all the more reason.

Your javascript example does not correspond to dictionary as well as:

var myDictionary = [];
myDictionary["namevalue1"] = "value1";
myDictionary["namevalue2"] = "value2";

Now, we can do everything with my code that we can do with yours, but it's not really modelling the same thing. Yours defines properties while mine associates values with keys. You've semantically created a structured object, I've created a flatter object though I have a bit more flexibilty in the case where I don't know what string I will use as the key (not that much more in js, since js's runtime flexibility means it's not too hard to dynamically add new properties if the key is a valid label.

Just like in Javascript, in C#:

If you've a small set of properties that are known at compile time, then a class with such properties most closely models your intent.

If you've a large set of properties or do not know them at compile time, then a dictionary will most closely model your intent.

The fact that these are likely to be the most performant for either cases is just a bonus, model your intent as best as the language allows first, think about stepping away from what does so later if absolutely necessary.

No different to JS really, except it's a bit stricter as to just which you're doing at a time (we can get around that strictness if we really need to, but do you?).

If you want to do the kind of duck typing that you do in javascript, but in C#, you could use the ExpandoObject. This is a .Net 4 class. You can dynamically set its properties like:

dynamic myObject = new ExpandoObject();
myObject.namevalue1 = "value1";
myObject.namevalue2 = "value2";

The nice trick that comes in handy with the ExpandoObject in reference to what you are trying to do is that you can access the properties on the ExpandoObject in the same manner as you would access a dictionary value:

var myDictionary = myObject as IDictionary<string, object>;
Console.WriteLine(myDictionary["namevalue1"]); // value1
Console.WriteLine(myDictionary["namevalue2"]); // value2

Keep in mind you are coming from a dynamic language( javascript ) to a static language( C# ) and the standards and paradigms are very different. Creating a class that represents the data model would be much faster and in general, better form than dynamic objects spewn about.

Classes are significantly faster than Dictionaries. However, Dictionaries are still very fast. Here is a .NET Fiddle comparing their performance: https://dotnetfiddle.net/NbFw4s

The results:

Dictionary read:  24,544,154 ops/sec
Object read:     383,327,796 ops/sec
-------------------------------------------
Dictionary write: 22,017,208 ops/sec
Object write:    228,458,287 ops/sec

As you can see, classes are an order of magnitude faster than Dictionaries. However, at 24 million operations per second, Dictionaries are still completely acceptable for all but the most performance-sensitive applications (and even then, I would be skeptical that Dictionaries would be the source of performance issues).

The code from the dotnetfiddle:

using System;
using System.Diagnostics;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Stopwatch stopwatch;
        var operations = 15000000;
        var dict = new Dictionary<string, string>() {{"Name", "Bob"}};
        var obj = new Person { Name = "Bob" };

        stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < operations; i++)
        {
            var firstName = dict["Name"];
        }
        stopwatch.Stop();
        Console.WriteLine("Dictionary read: " + (operations / stopwatch.Elapsed.TotalSeconds).ToString("N0") + " ops/sec");
        
        stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < operations; i++)
        {
            var firstName = obj.Name;
        }
        stopwatch.Stop();
        Console.WriteLine("Object read:    " + (operations / stopwatch.Elapsed.TotalSeconds).ToString("N0") + " ops/sec");
        
        Console.WriteLine("-------------------------------------------");
        
        stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < operations; i++)
        {
            dict["Name"] = "Jim";
        }
        stopwatch.Stop();
        Console.WriteLine("Dictionary write: " + (operations / stopwatch.Elapsed.TotalSeconds).ToString("N0") + " ops/sec");
        
        stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < operations; i++)
        {
            obj.Name = "Jim";
        }
        stopwatch.Stop();
        Console.WriteLine("Object write:    " + (operations / stopwatch.Elapsed.TotalSeconds).ToString("N0") + " ops/sec");
        
    }
    
    class Person {
        public string Name;
    }
}

The C# Dictionary class is strongly typed using generics. You specify both the type of the keys and the values when using it.

I'd recommend learning about the dictionary class as you are very likely to find it useful for many purposes.

It's hard to comment further without knowing more about your use case, but in general I wouldn't worry about performance of the Dictionary class until you know it's an issue, and refactor later if it is. (I bravely predict that it won't be).

It really depends on your use case. C# dictionaries are a lot more performant than you might generally expect from your JavaScript code. Plus, as The Don points out, "We should forget about small efficiencies, say about 97% of the time; premature optimization is the root of all evil" . I've provided a couple of examples that provide the same output as your sample JavaScript:

enum DictKeys
{
    nameValue1,
    nameValue2,
}

void Main()
{
    var myDictionary = new Dictionary<string, string>();
    myDictionary.Add("namevalue1", "value1");
    myDictionary.Add("namevalue2", "value2");

    Console.WriteLine(myDictionary["namevalue1"]); // "value1"

    var myDict2 = new Dictionary<DictKeys, string>();
    myDict2.Add(DictKeys.nameValue1, "value1");
    myDict2.Add(DictKeys.nameValue2, "value2");

    Console.WriteLine(myDict2[DictKeys.nameValue1]); // "value1"
}

Class with properties will give you a performance boost and intellisense support. On the other hand, dictionary can give you more flexibility, if you need it.

since you are using it for Data.... a "DataTable" which is a microsoft abstraction of exactly this, is basically a big dictionary. You may want to investigate DataTable as it has a whole lot of toys that come with it that MAY make your life a lot easier.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM