Ok, am I just not seeing how to do this or is there a fundamental problem with the approach?
Given the following desired public API:
[Fact]
public void GroupManagerCanAddNewGroupWithConnectionId()
{
var groupName = "ThisNewGroup";
var connectionId = "ThisNewConnection";
var sut = new GroupManager();
sut.Add(groupName, connectionId);
Assert.Contains(groupName, sut.Groups);
Assert.Contains(connectionId, sut.Groups[groupName]);
}
How do I achieve something like the following, which clearly is not legal as it does not compile:
private readonly ConcurrentDictionary<string, HashSet<string>> groups =
new ConcurrentDictionary<string, HashSet<string>>();
public IEnumerable<string> Groups { get { return this.groups.Keys; } }
public IEnumerable<string> Groups[string i] { get { return this.groups[i]; } }
public void Add(string groupName, string connectionSring)
{
groups.AddOrUpdate(
groupName,
new HashSet<string>(new string[1] { connectionSring }),
(conn, list) => { list.Add(conn); return list; });
}
Use an indexer in your class for accessing a dictionary by a key
public IEnumerable<string> this[string key]
{
get
{
return groups[key];
}
}
I knew it could be done. I added a wrapper class to manage access and then defined access by inheriting from IEnumerable and providing a property indexer. Then my group manager class became simple. Now my test passes.
public class GroupManager
{
private readonly GroupStore groups = new GroupStore();
public GroupStore Groups { get { return this.groups; } }
public void Add(string groupName, string connectionSring)
{
groups.Add(groupName, connectionSring);
}
}
public class GroupStore : IEnumerable<string>
{
private readonly ConcurrentDictionary<string, HashSet<string>> groupStore = new ConcurrentDictionary<string, HashSet<string>>();
public IEnumerable<string> this[string index] { get { return this.groupStore[index]; } }
public IEnumerator<string> GetEnumerator()
{
return groupStore.Keys.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public void Add(string groupName, string connectionSring)
{
//groupStore.AddOrUpdate(...);
}
}
Related
I have multiple classes containing duplicated code, especially members and most important a static method that will create a new instance of the class and returning this instance: either a previously created instance registered in a dictionary or a new instance by calling the constructor.
An interface is no option, because I have the static method. I tried to solve the problem by introducing a base class that implements this static method, but I can not find a way to create and return a spefific child class properly.
Below is a code example of the current situation with class A and class B showing duplicated code.
public class A
{
private static readonly IDictionary<string, A> Registry = new Dictionary<string, A>();
public string Name { get; set; }
public A(string name)
{
this.Name = name;
}
public static A GetA(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = new A(instanceName);
}
return newInstance;
}
}
}
And then in class B again there is a member Name and the GetX() Method.
public class B
{
private static readonly IDictionary<string, B> Registry = new Dictionary<string, B>();
public string Name { get; set; }
public B(string name)
{
this.Name = name;
}
public static B GetB(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = new B(instanceName);
}
return newInstance;
}
}
}
Is there a possibility to avoid this kind of code duplication by introducing a base class or any other way?
This might be a little cleaner:
public class B: RegistryInstance<B>
{
public string Name { get; set; }
public B(string name)
{
this.Name = name;
}
}
public class A : RegistryInstance<A>
{
public string Name { get; set; }
public A(string name)
{
this.Name = name;
}
}
public abstract class RegistryInstance<T> where T:class
{
protected static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public static T GetInstance(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = (T)Activator.CreateInstance(typeof(T), new object[] { instanceName });
Registry.Add(instanceName, newInstance);
}
return newInstance;
}
}
}
Are you looking for a generic base class?
public abstract class BaseRegistryGetter<T>
{
private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public string Name { get; set; }
public BaseRegistryGetter(string name)
{
this.Name = name;
}
public static T GetValue (string instanceName, Func<string, T> creator) {
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = creator(instanceName);
}
return newInstance;
}
}
}
And then use it like this:
public class A : BaseRegistryGetter<A>
{
public A(string name) : base(name)
{
}
public static A GetA(string instanceName)
{
return BaseRegistryGetter<A>.GetValue(instanceName, s => new A(s));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry when you were creating a new instance.
class Program
{
static void Main(string[] args)
{
A a1 = A.GetInstance("a");
A a2 = A.GetInstance("aa");
A a3 = A.GetInstance("a");
B b1 = B.GetInstance("a");
B b2 = B.GetInstance("aa");
B b3 = B.GetInstance("a");
Console.WriteLine(a1 == a2); //false
Console.WriteLine(a1 == a3); //true
Console.WriteLine(b1 == b2); //false
Console.WriteLine(b1 == b3); //true
Console.ReadKey();
}
}
public class A : Generic<A>
{
public A(string name)
: base(name)
{
}
}
public class B : Generic<B>
{
public B(string name)
: base(name)
{
}
}
public abstract class Generic<T> where T : Generic<T>
{
private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public string Name { get; set; }
public Generic(string name)
{
this.Name = name;
}
public static T GetInstance(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = (T)Activator.CreateInstance(typeof(T), instanceName);
Registry.Add(instanceName, newInstance);
}
return newInstance;
}
}
}
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
public class Base
{
static readonly IDictionary<string, Base> Registry =
new Dictionary<string, Base>();
protected static Base GetBase(string instanceName,
Func<Base> creator)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = creator();
}
return newInstance;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
public class A: Base
{
public A(string instanceName)
:base(instanceName)
{
}
public static A GetA(string instanceName)
=> GetBase(instanceName, () => new A(instanceName)) as A;
}
public class B: Base
{
public B(string instanceName)
:base(instanceName)
{
}
public static B GetB(string instanceName)
=> GetBase(instanceName, () => new B(instanceName)) as B;
}
I have a class that inherits from List<T> and add one more class property
public class DrivenList : List<int>
{
public string Name {get;set;}
private DrivenList() { }
public DrivenList(string name) { this.Nname = name; }
}
When JSON serializing the object using Newtonsoft.Json, I get only the list item. ( [1,2,3] )
Any ideas how to add the Name property to the results?
Solved: by adding this attribute to the list
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class DrivenList : List<int>
As far as I know with Newtonsoft all you can do is something like this:
[JsonObject(MemberSerialization = MemberSerialization.Fields)]
public class DrivenList : List<int>
{
[JsonProperty]
public string Name { get; set; }
private DrivenList() { }
public DrivenList(string name) { this.Name = name; }
}
But this will add you unwanted (maybe) fields.
Personally I will do composition instead of inheritance:
public class DrivenList
{
public string Name { get; set; }
public List<int> Items { get; set; }
private DrivenList() { }
public DrivenList(string name) { this.Name = name; }
}
What .NET version are you using and what serializer?
If you are using the standard serializer, then adding [DataMember] annotations would be the answer.
https://msdn.microsoft.com/en-us/library/bb412179(v=vs.110).aspx
But I would suggest to use Json.NET http://www.newtonsoft.com/json
Update:
I would suggest not to directly inherit to List
class Program
{
static void Main(string[] args)
{
var list = new Driven("Ragnarok");
list.Items.Add(1);
list.Items.Add(2);
string json = JsonConvert.SerializeObject(list);
Console.WriteLine(json);
Console.ReadKey();
}
}
public class Driven
{
public Driven(string name)
{
this.Name = name;
}
public List<int> Items { get; set; } = new List<int>();
public string Name { get; set; }
}
Output:
{"Items":[1,2],"Name":"Ragnarok"}
An alternative solution could be to delegate the implementation of IList to your own property. Then you can use the DataContractSerializer. The upside of this is that all the existing C#-code (and all your tests) will still be intact, and no custom logic is needed for serializing it.
If that's not an option and you really want to use NewtonSoft, then you should take a look at this answer, and create your own JsonConverter.
How to serialize/deserialize a custom collection with additional properties using Json.Net
The problem is the following: when an object implements IEnumerable,
JSON.net identifies it as an array of values and serializes it
following the array Json syntax (that does not include properties)
Here's an example that use DataContractSerializer:
JsonHelper from CodeProject
public class JsonHelper
{
/// <summary>
/// JSON Serialization
/// </summary>
public static string JsonSerializer<T>(T t)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
MemoryStream ms = new MemoryStream();
ser.WriteObject(ms, t);
string jsonString = Encoding.UTF8.GetString(ms.ToArray());
ms.Close();
return jsonString;
}
/// <summary>
/// JSON Deserialization
/// </summary>
public static T JsonDeserialize<T>(string jsonString)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
T obj = (T)ser.ReadObject(ms);
return obj;
}
}
And the new implementation of your class.
[DataContract]
public class DrivenList : IList<int>
{
[DataMember]
public List<int> Items = new List<int>();
[DataMember]
public string Name { get; set; }
private DrivenList() { }
public DrivenList(string name) { this.Name = name; }
#region Implementation of IList
public IEnumerator<int> GetEnumerator()
{
return Items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)Items).GetEnumerator();
}
public void Add(int item)
{
Items.Add(item);
}
public void Clear()
{
Items.Clear();
}
public bool Contains(int item)
{
return Items.Contains(item);
}
public void CopyTo(int[] array, int arrayIndex)
{
Items.CopyTo(array, arrayIndex);
}
public bool Remove(int item)
{
return Items.Remove(item);
}
public int Count
{
get { return Items.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public int IndexOf(int item)
{
return Items.IndexOf(item);
}
public void Insert(int index, int item)
{
Items.Insert(index, item);
}
public void RemoveAt(int index)
{
Items.RemoveAt(index);
}
public int this[int index]
{
get { return Items[index]; }
set { Items[index] = value; }
}
#endregion
}
And an example usage:
var list = new DrivenList("foo");
list.Add(1);
list.Add(3);
list.Add(5);
var json = JsonHelper.JsonSerializer(list);
Output:
{"Items":[1,3,5],"Name":"foo"}
Apply the DataContract attribute for the class and DataMember attribute for the properties.
[DataContract]
public class DrivenList : List<int>
{
[DataMember]
public string Name {get;set;}
private DrivenList() { }
public DrivenList(string name) { this.Nname = name; }
}
I have a class Properties and in that I have defined a dictionary like this :
public class Properties
{
public IDictionary<string, string> ExtendedProperties
{
get;
set;
}
}
In the dictionary, there will be 3 keys always present say Name,Number and Age with the option of adding more KeyValuePairs during runtime.
I want to have the 3 keys described above to be present in the dictionary by default while initializing it in my code so that I can use it directly like this:
Properties objProps = new Properties();
objProps.ExtendedProperties["Name"] = "SomeName";
I know I can achieve this in my code by adding the KeyValuePair to the dictionary but I was hoping to have it setup directly in the class using get-set to include the 3 keys. I could not find any solution that does that in the class itself. I looked into this Creating dictionaries with predefined keys but did not find it satisfactory.
how can I achieve this?
Since C# 6 you can do something like:
using System;
using System.Collections.Generic;
public class Properties
{
public IDictionary<string, string> ExtendedProperties { get; set; }
public Properties(string name, string number, string age)
{
this.ExtendedProperties = new Dictionary<string, string>()
{
["Name"] = name,
["Number"] = number,
["Age"] = age
};
}
}
As you can see you need to define it in the constructor.
There is also some cool function you might want to use:
public int this[int param]
{
get { return array[param]; }
set { array[param] = value; }
}
Documentation
If you add something like this, you can do new Properties()["Name"]
Example with your code:
using System;
using System.Collections.Generic;
public class Properties
{
private IDictionary<string, string> extendedProperties;
public string this[string key]
{
get { return extendedProperties[key]; }
set { extendedProperties[key] = value; }
}
public Properties()
{
this.extendedProperties = new Dictionary<string, string>()
{
["Name"] = "something",
["Number"] = "something",
["Age"] = "something"
};
}
}
Like this:
public class Properties
{
public IDictionary<string, string> ExtendedProperties
{
get;
set;
}
public Properties()
{
this.ExtendedProperties = new Dictionary<string, string>()
{
{ "Name", String.Empty },
{ "Number", String.Empty },
{ "Age", String.Empty },
};
}
}
You might want to have a look at some documentation: https://msdn.microsoft.com/en-us/library/bb531208.aspx
How about adding the 3 entries in the constructor?
using System;
using System.Collections.Generic;
namespace My.Namespace
{
public class Properties
{
public IDictionary<string, string> ExtendedProperties { get; set; }
public Properties()
{
ExtendedProperties = new Dictionary<string, string>
{
["Name"] = String.Empty,
["Number"] = String.Empty,
["Age"] = String.Empty
};
}
}
}
You can do this.
public class Properties
{
public IDictionary<string, string> ExtendedProperties
{
get;
set;
}
public Properties(string [] fields)
{
ExtendedProperties = new Dictionary<string, string> ();
foreach(var s in fields)
{
ExtendedProperties.Add(s,string.Empty);
}
}
}
Usage :
Properties p = new Properties(new [] {"Name","Number", "Age"});
Working fiddler code
I would go with implementing IDictionary<string, string> because it is more safe and easier to extend with other keys: (long class to follow)
class Properties : IDictionary<string, string>
{
private Dictionary<string, string> _staticProps;
private Dictionary<string, string> _otherProps;
public Properties()
{
_staticProps = new Dictionary<string, string>
{
{"Name", "" },
{"Number", "" },
{"Age", "" }
};
_otherProps = new Dictionary<string, string>();
}
public ICollection<string> Keys
{
get
{
return (ICollection<String>)_otherProps.Keys.Concat(_staticProps.Keys);
}
}
public ICollection<string> Values
{
get
{
return (ICollection<String>)_otherProps.Values.Concat(_staticProps.Values);
}
}
public int Count
{
get
{
return _otherProps.Count + _staticProps.Count;
}
}
public bool IsReadOnly
{
get
{
throw new NotImplementedException();
}
}
public string this[string key]
{
get
{
if (_otherProps.ContainsKey(key))
{
return _otherProps[key];
}
if(_staticProps.ContainsKey(key))
{
return _staticProps[key];
}
throw new KeyNotFoundException(key);
}
set
{
if (_otherProps.ContainsKey(key) || _staticProps.ContainsKey(key))
{
throw new ArgumentException("key exists: " + key);
}
_otherProps[key] = value;
}
}
public bool ContainsKey(string key)
{
return _otherProps.ContainsKey(key) || _staticProps.ContainsKey(key);
}
public void Add(string key, string value)
{
_otherProps.Add(key, value);
}
public bool Remove(string key)
{
if (_staticProps.ContainsKey(key))
{
throw new ArgumentException("key is static, cannot be removed: " + key);
}
return _otherProps.Remove(key);
}
public bool TryGetValue(string key, out string value)
{
return _otherProps.TryGetValue(key, out value) || _staticProps.TryGetValue(key, out value);
}
public void Add(KeyValuePair<string, string> item)
{
if (_staticProps.ContainsKey(item.Key))
{
throw new ArgumentException("key exist an is static: " + item.Key);
}
_otherProps.Add(item.Key, item.Value);
}
public void Clear()
{
_otherProps.Clear();
foreach (var key in _staticProps.Keys)
{
_staticProps[key] = string.Empty;
}
}
public bool Contains(KeyValuePair<string, string> item)
{
return _otherProps.Contains(item) || _staticProps.Contains(item);
}
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
{
// define yourself how you want to handle arrayIndex between the two dictionaries
}
public bool Remove(KeyValuePair<string, string> item)
{
if (_staticProps.ContainsKey(item.Key))
{
throw new ArgumentException("key is static, cannot be removed: " + item.Key);
}
return _otherProps.Remove(item.Key);
}
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return _otherProps.Concat(_staticProps).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _otherProps.Concat(_staticProps).GetEnumerator();
}
}
I would encapsulate this logic in property itself:
public class Properties
{
private IDictionary<string, string> _extendedProperties;
public IDictionary<string, string> ExtendedProperties
{
get
{
return
_extendedProperties == null ?
new Dictionary<string, string>() { { "Name", "" }, { "Number", "" }, { "Age", "" } } :
_extendedProperties;
}
set
{
_extendedProperties = value;
//here you can also check if value misses those key to add them to _extendedProperties
}
}
}
I'm playing around with Dictionaries and the new fancy 4.0 dynamic types inside a dictionary.
I have a Dictionary:
Dictionary<dynamic, dynamic> dynamicDic
And I populate it like this:
dynamicDic.Add("First", new Class1());
dynamicDic.Add("Second", new Class2());
For the sake of testing/practising Class1 and Class2 are quite simple:
public class Class1
{
public string Element { get; set; }
public List<Class2> Class2 { get; set; }
}
public class Class2
{
public string Property { get; set; }
public string Field;
}
I create two other classes that map class1 and class2 and they are virtually the same so ClassMap1 and ClassMap2. I'll just include CalssMap1 though:
public class ClassMap1: BaseClassMap1
{
public ClassMap1()
{
var r = new Class1();
Children = new Dictionary<string, dynamic>
{
{"Element", r.GetType().GetProperty("Element")},
{"Class1", r.GetType().GetProperty("Class1")}
};
Name = "Root";
ObjectType = typeof (Class1);
Parent = "RootElement";
HasParent = false;
HasChildren = true;
IsClass = r.GetType().IsClass;
}
}
And I create a base class: BaseClass1()
public class BaseClass1
{
private String _Name;
public String Name
{
get { return _Name; }
set { _Name = value; }
}
private Type _ObjectType;
public Type ObjectType
{
get { return _ObjectType; }
set { _ObjectType = value; }
}
private String _Parent;
public String Parent
{
get { return _Parent; }
set { _Parent = value; }
}
private Dictionary<string, dynamic> _Children;
public Dictionary<string, dynamic> Children
{
get { return _Children; }
set { _Children = value; }
}
private bool _HasParent;
public bool HasParent
{
get { return _HasParent; }
set { _HasParent = value; }
}
private bool _HasChildren;
public bool HasChildren
{
get { return _HasChildren; }
set { _HasChildren = value; }
}
private bool _IsClass;
public bool IsClass
{
get { return _IsClass; }
set { _IsClass = value; }
}
}
I populate the classes with data, not really important what data :)
Yet when I try to access the values through a Linq statement:
var a = _classObjects.SingleOrDefault(x => x.Key == node.Name).Value;
a only gives me:-
a.Equals(), a.GetType(), a.GetEnumerator() or a.ToString()
I would like to be able to have it do this instead (with intellisense)...
a.Children
a.Name
a.HasParent
etc...
Anyone got any ideas where I'm going wrong?
Oops got that completely wrong... Sorry :|
Edited above...
dynamic classes are all about run-time (NOT compile-time) discovery. How do you expect Intellisense to know what to do?
Using dynamic classes incurs a high performance overhead. I really suggest that you make it: Dictionary<string, dynamic> dynamicDic.
Or define a MyBaseClass and make it: Dictionary<string, MyBaseClass> myDic.
How to implement IEnumerator on this class so that I can use it in foreach loop.
public class Items
{
private Dictionary<string, Configuration> _items = new Dictionary<string, Configuration>();
public Configuration this[string element]
{
get
{
if (_items.ContainsKey(element))
{
return _items[element];
}
else
{
return null;
}
}
set
{
_items[element] = value;
}
}
}
In this example Configuration is a simple class with few properties.
Just an example to implement typesafe IEnumerable and not IEnumerator which you will be able to use in foreach loop.
public class Items : IEnumerable<Configuration>
{
private Dictionary<string, Configuration> _items = new Dictionary<string, Configuration>();
public void Add(string element, Configuration config) {
_items[element] = config;
}
public Configuration this[string element]
{
get
{
if (_items.ContainsKey(element))
{
return _items[element];
}
else
{
return null;
}
}
set
{
_items[element] = value;
}
}
public IEnumerator<Configuration> GetEnumerator()
{
return _items.Values.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.Values.GetEnumerator();
}
}
Regards.
You should be able to implement IEnumerator like this:
public class Items : IEnumerator<KeyValuePair<string, Configuration>>
{
private Dictionary<string, Configuration> _items = new Dictionary<string, Configuration>();
public Configuration this[string element]
{
get
{
if (_items.ContainsKey(element))
{
return _items[element];
}
else
{
return null;
}
}
set
{
_items[element] = value;
}
}
int current;
public object Current
{
get { return _items.ElementAt(current); }
}
public bool MoveNext()
{
if (_items.Count == 0 || _items.Count <= current)
{
return false;
}
return true;
}
public void Reset()
{
current = 0;
}
public IEnumerator GetEnumerator()
{
return _items.GetEnumerator();
}
KeyValuePair<string, Configuration> IEnumerator<KeyValuePair<string, Configuration>>.Current
{
get { return _items.ElementAt(current); }
}
public void Dispose()
{
//Dispose here
}
}
But as already noted you could also just implement IEnumerable.
You don't need to implement IEnumerable or any interface. In order to be able to use your class in a foreach, all that you need is to add an instance method to your class with the follwing signature:
IEnumerator GetEnumerator()