none
Software architecture for a dictionary with different types RRS feed

  • Question

  • Hello,
    I want to create a dictionary with different types.
    Can I create this with an interface?
    When I create a query for the key, how do I get the type?
    Does this pattern have a specific name?
    Do I need a basic class yet?
    I do not want to create different dictionaries.
    Thanks for any tips in advance.
    With best regards Markus
    private void btnTest_Click(object sender, EventArgs e)
    {
    	Dictionary<string, IObjectVariable> dictVariables = new Dictionary<string, IObjectVariable>();
    	dictVariables.Add("MyDate", new Date());
    	dictVariables.Add("MyCounter", new Counter(44, 22));
    	dictVariables.Add("MyFixText", new Field());
    
    	var qry = dictVariables.Where(x => x.Key == "MyCounter").FirstOrDefault();
    	Counter obj = qry.Value as Counter;
    	Trace.WriteLine($"{obj.StartValue}, {obj.CurrentValue}");
    	
    
    	
    			
    public interface IObjectVariable
    {
    	string ToString();
    }
    
    public class Converter : IObjectVariable
    {
    	public override string ToString()
    	{
    		return "Converter";
    	}
    }
    
    public class Field : IObjectVariable
    {
    	public override string ToString()
    	{
    		return "Field";
    	}
    }
    
    public class Date : IObjectVariable
    {
    	public override string ToString()
    	{
    		return "Date";
    	}
    }
    
    public class Counter : IObjectVariable
    {
    	public int StartValue = 0;
    	public int CurrentValue = 0;
        public int Step = 1;
    
    	public Counter(int start, int current)
    	{
    		StartValue = start;
    		CurrentValue = current;
    	}
    
    	public override string ToString()
    	{
    		return "Counter";
    	}
    }


    Saturday, June 30, 2018 10:00 AM

Answers

  • The problem with you code is: It contains redundancy. Your interface is not necessary, cause Object already implements ToString(). Thus you can simply reduce your sample to use Object as I proposed. 

    And the type is simply queried with the default methods. E.g.

    namespace ConsoleApp1
    {
        using System;
        using System.Collections.Generic;
    
        public class A { public void SayHello() { Console.WriteLine("Hello."); } }
        public class B { public void ShoutHello() { Console.WriteLine("HELLO!!!"); } }
    
        class Program
        {
            static void Main(string[] args)
            {
                Dictionary<string, object> dictionary = new Dictionary<string, object>();
                dictionary.Add("1", new A());
                dictionary.Add("2", new B());
                foreach (var entry in dictionary)
                {
                    Console.WriteLine($"{entry.Key} is {entry.Value.GetType()}");
                    if( entry.Value is A) {
                        (entry.Value as A).SayHello();
                    }
    
                    if (entry.Value is B)
                    {
                        (entry.Value as B).ShoutHello();
                    }
                }
    
                Console.WriteLine("Done.");
                Console.ReadLine();
            }
        }
    }

    Monday, July 2, 2018 11:53 AM
  • What do you want to do with it? If you have it as you wrote it cause dictionary will be created with each click event and collected when method ends. It does not make sense. 

    There could be design pattern known as Service Locator. It is static class with (Un)Register and Get method. In behind of it is dictionary of objects and Register method is used to add object into dictionary. Get method is implemented as generic and returns object from Dictionary.

    public static class ServiceLocator
    {
        private static Dictionary<string, object> _dictionary=new Dictionary<string, object>();
      
        public static void Register<T>(T value)
        {
            if (!_dictionary.ContainsKey(typeof(T).Name)
                _dictionary.Add(typeof(T).Name, value);
        }
    
        public static T Get<T>()
        {
            //if type not exists it throws exception.
            //It is better than return null object.
            //You can rewrite it as bool TryGet<T>(out T value)
            return _dictionary[typeof(T).Name];
        }
    
        public static void Unregister<T>()
        {
            if (_dictionary.ContainsKey(typeof(T).Name))
                _dictionary.Remove(typeof(T).Name);
        }
    }

    This code is not thread safety. You can register object of some instance and use it when you need. I use this pattern when I need register service (logging) in presentation layer (when user action starts) and logging object could be used in data layer to log sql command. 

    Be being as generic return type you might not to use cast object to type which you need. You can constrain T to your base class or interface as you want when you don't want to register another types. 

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters



    • Edited by Petr B Sunday, July 1, 2018 6:01 PM
    • Marked as answer by Markus Freitag Monday, July 2, 2018 5:05 PM
    Sunday, July 1, 2018 5:57 PM

All replies

  • What's wrong with Dictionary<string, object>?
    Saturday, June 30, 2018 10:32 AM
  • I think interface is not necessary. Instead of using string key as MyFixText. You can use nameof(Field). It creates "relation" to your objects. Or you can use GetType().Name as key. 

    var qry = dictVariables.Where(x => x.Key == "MyCounter").FirstOrDefault();

    This expression should be written as
    var qry = dictVariables.FirstOrDefault(x => x.Key == "MyCounter");

    Saturday, June 30, 2018 6:04 PM
  • What's wrong with Dictionary<string, object>?

    Nothing wrong, my question is, is this a good solution, a Right solution and is there a Name for this pattern, like Factory Pattern or Singleton.

    Regards Markus

    Sunday, July 1, 2018 11:35 AM
  • What do you want to do with it? If you have it as you wrote it cause dictionary will be created with each click event and collected when method ends. It does not make sense. 

    There could be design pattern known as Service Locator. It is static class with (Un)Register and Get method. In behind of it is dictionary of objects and Register method is used to add object into dictionary. Get method is implemented as generic and returns object from Dictionary.

    public static class ServiceLocator
    {
        private static Dictionary<string, object> _dictionary=new Dictionary<string, object>();
      
        public static void Register<T>(T value)
        {
            if (!_dictionary.ContainsKey(typeof(T).Name)
                _dictionary.Add(typeof(T).Name, value);
        }
    
        public static T Get<T>()
        {
            //if type not exists it throws exception.
            //It is better than return null object.
            //You can rewrite it as bool TryGet<T>(out T value)
            return _dictionary[typeof(T).Name];
        }
    
        public static void Unregister<T>()
        {
            if (_dictionary.ContainsKey(typeof(T).Name))
                _dictionary.Remove(typeof(T).Name);
        }
    }

    This code is not thread safety. You can register object of some instance and use it when you need. I use this pattern when I need register service (logging) in presentation layer (when user action starts) and logging object could be used in data layer to log sql command. 

    Be being as generic return type you might not to use cast object to type which you need. You can constrain T to your base class or interface as you want when you don't want to register another types. 

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters



    • Edited by Petr B Sunday, July 1, 2018 6:01 PM
    • Marked as answer by Markus Freitag Monday, July 2, 2018 5:05 PM
    Sunday, July 1, 2018 5:57 PM
  • It's not a pattern.  It's just a data structure.

    Tim Roberts, Driver MVP Providenza & Boekelheide, Inc.

    Monday, July 2, 2018 6:26 AM
  • The things which comes into mind: Covariance and contravariance.

    Monday, July 2, 2018 7:41 AM
  • I think, it depends. What I wrote is something like container. You can add/remove/get some instance ... This is very simple example but princip of it is centralize your services to one place where you can get it when you need. There could be service repository, factory, etc... inside if you want. 

    But I think it is nice example how to store instances of different types in one place. 

    If encapsulation of dictionary is data structure, I say repository pattern is data structure too. There are Add/Remove/Get method and I don't know anything about inside representation of repository. There could be dictionary too when it is memory repository. So is repository pattern data structure too? 

    Monday, July 2, 2018 9:27 AM
  • The problem with you code is: It contains redundancy. Your interface is not necessary, cause Object already implements ToString(). Thus you can simply reduce your sample to use Object as I proposed. 

    And the type is simply queried with the default methods. E.g.

    namespace ConsoleApp1
    {
        using System;
        using System.Collections.Generic;
    
        public class A { public void SayHello() { Console.WriteLine("Hello."); } }
        public class B { public void ShoutHello() { Console.WriteLine("HELLO!!!"); } }
    
        class Program
        {
            static void Main(string[] args)
            {
                Dictionary<string, object> dictionary = new Dictionary<string, object>();
                dictionary.Add("1", new A());
                dictionary.Add("2", new B());
                foreach (var entry in dictionary)
                {
                    Console.WriteLine($"{entry.Key} is {entry.Value.GetType()}");
                    if( entry.Value is A) {
                        (entry.Value as A).SayHello();
                    }
    
                    if (entry.Value is B)
                    {
                        (entry.Value as B).ShoutHello();
                    }
                }
    
                Console.WriteLine("Done.");
                Console.ReadLine();
            }
        }
    }

    Monday, July 2, 2018 11:53 AM
  • >This code is not thread safety.
    Would i need a thread safe dictionary? ConcurrentDictionary?

    I think it is a pattern, isn't it?

    Regards Markus

    Monday, July 2, 2018 5:03 PM
  • entry.Value is A

    That  is it , looks good. Thanks.

    Regards Markus

    Monday, July 2, 2018 5:05 PM
  • You need lock some object to permit another thread to (un)register instance when it is (un)registering by current thread. 
    Monday, July 2, 2018 10:19 PM
  • In my view, a "pattern" involves not only a data structure, but the methods and tactics one uses to access and manipulate that data structure.  The interfaces, if you will.

    As you say, the "repository" pattern specifies the Add/Remove/Get methods, but does not dictate the underlying data structure.  Dictionary<string,object> certainly can be used as the basis of the repository pattern, but I think it is inaccurate to say that the data structure IS a pattern.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Monday, July 2, 2018 11:29 PM
  • I think it is about terminology only. As you can see Service locator pattern (it is pattern name) implementation there exists implementation as I wrote. But implementation is not important. Important is that there is structure to store and get some different type instances. This idea could be pattern :) 

    In my view (as I read it in many books and articles) pattern is some good using of complex problem solution. I think terminology is important because I meet with repository named as Module. There were Add/Remove/Get methods so I said it is repository, isn't it? Programmer asked me what is repository. Try type to google repository pattern. 

    What is better result when type it into google/bing - repository data structure or repository pattern? It is about common dictionary. As you can read in many articles it is very very important to use common dictionary to understand what other mean. It is not about pattern/data structure only. In DDD is used ubiquitous language to understand. So why if you can read many articles/books where is written Service Locator Pattern, I would say Service Locator is data structure only? When you say Service Locator Pattern many programmers know what it is, when to use it and how to use it. So pattern is some solution which we used in past and it was good using of solution and we can use it in future when there will be similar situation as in past when we used it and we can adopt this solution for next using. 

    So if there is problem with share some instances (services) through some layers in application I know there could be used Service Locator Pattern which defines access to instances by some methods and simple implementation is as I wrote.

    Tuesday, July 3, 2018 5:06 AM