I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
And enable me to add the following:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
I know that I can do it for a list of strings, for example, using this syntax:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
but I'd like to do it for a generic list if possible...
2 questions then:
Is it possible?
What's the syntax?
EDIT: Now I've reread the question...
You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:
public void Add<T>(string key, List<T> list)
(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)
You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.
EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...
No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.
However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.
Would something like this work?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Basically it wraps all the casting behind the scenes for you.
How about Dictionary<string, dynamic>? (assuming you're on C# 4)
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Source: https://stackoverflow.com/a/5038029/3270733
I prefer this way of putting generic types into a collection:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
But you do lose the type checks at compile time.
I came to a type safe implementation using ConditionalWeakTable.
public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();
public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}
public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}
public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}
public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}
It can be used like this:
/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();
public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}
public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}
return dictionary.TryGetValue(original, out clone);
}
}
See also this question where the type of the values is stored in as a generic parameter of the keys.
We're using lots of reflection to create an extensible administration tool. We needed a way to register items in the global search in the module definition. Each search would return results in a consistent way, but each one had different dependencies. Here's an example of us registering search for a single module:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
In the background during module registration, we iterate over every module and add the Func to a SearchTable with an instance of:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Then when we finally call it, we do it with reflection:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
I didn't find what I was looking for here but after reading I think it might be what is being asked for so an attempt to answer.
The problem is that when you use Dictionary it is a closed constructed type and all elements must be of the TValue type. I see this question in a number of places without a good answer.
Fact is that I want indexing but each element to have a different type and based on the value of TKey we already know the type. Not trying to get around the boxing but trying to simply get more elegant access something like DataSetExtensions Field. And don't want to use dynamic because the types are known and it is just not wanted.
A solution can be to create a non generic type that does not expose T at the class level and therefore cause the TValue part of the dictionary to be closed constructed. Then sprinkle in a fluent method to help initialization.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Other posibility it's to use the variable dynamic.
For example:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>();
d.Add("Key", new List<dynamic>());
the variable dynamic resolve the type on runtime.
No, but you can use object instead of generic type.
Long answer:
The current version of C# will not allow you to make entries of generic type in a dictionary. Your options are either a) create a custom class that is the same as a dictionary except allow it to accept generic types, or b) make your Dictionary take values of type object. I find option b to be the simpler approach.
If you send lists of specific types, then when you go to process the lists you will have to test to see what kind of list it is. A better approach is to create lists of objects; this way you can enter integers, strings, or whatever data type you want and you don't necessarily have to test to see what type of object the List holds. This would (presumably) produce the effect you're looking for.
Here is a short console program that does the trick:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";
lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);
lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");
dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);
foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();
foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}
One of the way is to create a Dictionary value with type "object" like:
Dictionary<string, object> d = new Dictionary<string, object>();
So, here object datatype is used as a generic datatype, you can put anything in this as a value.
Or it's possible to use generic Type like this
public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}
Related
Because of business decisions which are above my paygrade, I need to parse and merge multiple XML files.
In order to cut down on redundant code, I have this map:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(List<A>)},
{"b.xml", typeof(List<B>)},
{"c.xml", typeof(List<C>)},
{"d.xml", typeof(List<D>)},
// etc.
};
Because how this map gets used, after downloading and parsing all the XMLs, the result is of type Dictionary<string, object> where the key is the same as the keys in the above map and the value is of the type specified in the map, as result of executing this code with DownloadFiles(config):
private static Dictionary<string, object> DownloadFiles(IConfigurationRoot config) {
Dictionary<string, object> dataListByFileNames = new Dictionary<string, object>();
listTypeByFileName.Keys.ToList()
.ForEach(name => dataListByFileNames.Add(name, DownloadData(name, config)));
return dataListByFileNames;
}
private static object DownloadData(string name, IConfigurationRoot config) {
_ = listTypeByFileName.TryGetValue(name, out Type listType);
return new XmlSerializer(listType, new XmlRootAttribute("Document"))
.Deserialize(new StringReader(DownloadFromBlobStorage(name, config).ToString()));
}
private static CloudBlockBlob DownloadFromBlobStorage(string filetoDownload, IConfigurationRoot config) {
return CloudStorageAccount.Parse(config["AzureWebJobsStorage"])
.CreateCloudBlobClient()
.GetContainerReference(config["BlobStorageContainerName"])
.GetBlockBlobReference(filetoDownload);
First question: Is there a way I can make the return more typesafe? Perhaps using parameterized types?
The second part of the problem is actually consuming this Dictionary.
For each type in this Dictionary, I now need a function like:
private void AddA(Dictionary<string, object> dataByFileNames) {
if (dataByFileNames.TryGetValue("a.xml", out object data)) {
List<A> aList = (List<A>)data;
aList.ForEach(a =>
doSomethingWithA(a);
);
}
}
private void AddB(Dictionary<string, object> dataByFileNames) {
if (dataByFileNames.TryGetValue("b.xml", out object data)) {
List<B> bList = (List<B>)data;
bList.ForEach(b =>
doSomethingWithB(b);
);
}
}
// etc.
As I already have the list of filenames to types (top of this question), I feel there should be some way to abstract the above so it does not need to be repeated again and again and again.
Note, it may be significant that every type (A, B, C, D, etc. all have a property string Id which will be definitely be needed for all doStringWithX() methods... if useful, I can create an interface to get this. It is okay if I need to caste to the correct type within each doStringWithX() or when invoking each of these methods.c
First, instead of storing the List<T> type in the dictionary, just store the underlying generic type:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(A)},
{"b.xml", typeof(B)}
// etc.
That's going to make future steps a little bit easier. When deserializing, create the generic list type. After getting the type from the dictionary, you can do:
var listType = typeof(List<>).MakeGenericType(typeRetrievedFromDictionary);
Once you've deserialized it, cast it as IList. That's effectively casting it as a list of object. That's okay. Because you deserialized using a specific type, every item in the list will be of the expected type.
Create a dictionary for the type-safe methods you want to invoke on every time in list.
Dictionary<Type, Action<object>> methodsToInvokeByType;
Add methods to the dictionary:
doSometingMethods.Add(typeof(A), dataItem => DoSomethingWithA((A)dataItem));
doSometingMethods.Add(typeof(B), dataItem => DoSomethingWithB((B)dataItem));
Now, once you've got your IList full of objects, you retrieve the type-safe method to invoke:
var methodToInvoke = methodsToInvokeByType[typeRetrievedFromDictionary];
Then do this:
foreach(object itemInList in list) // this is your deserialized list cast as IList
{
methodToInvoke(itemInList);
}
So if the type is A, you'll be invoking
DoSomethingWithA((A)itemInList)
It's not pretty. Bridging between code that uses objects and Type and type-safe generic code can be messy. But ultimately the goal is that whatever those final methods are - DoSomethingWithA, DoSomethingWithB, etc., at least those are type-safe.
You can simplify some more:
Create a class that deserializes a list and passes it off to a method for processing, and an interface:
public interface IXmlFileProcessor
{
void Process(byte[] xmlFile);
}
public class XmlFileProcessor<T> : IXmlFileProcessor
{
private readonly Action<T> _doSomething;
public XmlFileProcessor(Action<T> doSomething)
{
_doSomething = doSomething;
}
public void Process(byte[] xmlFile) // or string or whatever
{
// deserialize into a List<T>
foreach (T item in deserializedList)
_doSomething(item);
}
}
Then create a Dictionary<Type, IXmlFileProcessor> and populate it:
fileProcessors.Add(typeof(A), new XmlFileProcessor<A>(SomeClass.DoSomethingWithA));
fileProcessors.Add(typeof(B), new XmlFileProcessor<B>(SomeClass.DoSomethingWithB));
That approach (injecting the Action) is intended to keep the "do something" method decoupled from the class responsible for deserialization. DoSomething could also be a generic method in XmlFileProcessor<T>. There are different ways to compose those classes and add them to that dictionary. But either way, having determined the type, you just retrieve the correct type-specific processor from the dictionary, pass your file to it, and it does the rest.
That approach bridges the generic/non-generic gap by making the class - XmlFileProcessor<T> - generic, but having it implement a non-generic interface. It works as long as you take steps (using the dictionary) to ensure that you're selecting the correct implementation for whatever type you're deserializing.
I am trying to build a dictionary where the key is a property of the value object. However I would like to construct the value object in the dictionary's add method. Is there a way to do this without using an intermediate variable?
For example I would like to do the following, but of course the key value isn't available when needed.
Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>{
{someComplexObject.Key, new SomeComplexObject {Key = 1, Name = "FooBar"},
{someComplexObject.Key, new SomeComplexObject {Key = 2, Name = "FizzBang"}
};
Do I have to do it this ugly way:
Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>();
SomeComplexObject value1 = new SomeComplexObject{Key=1,Name = "FooBar"};
dict.Add(value1.Key,value1);
SomeComplexObject value2 = new SomeComplexObject{Key=2,Name = "FizzBang"};
dict.Add(value.Key,value2);
I don't think this is the same question as
How to use an object's identity as key for Dictionary<K,V>
because I am not asking specifically about the key of a dictionary but if there is a way to have access to a objects property when the object is not being created until later in the methods parameter list.
I don't think an extension method (as proposed in comments) is really what you want here, as it's only a partial solution. I.e. you would have to write a new extension method for each dictionary value type you wanted to use, which negates the whole point of asking for a general solution.
Instead, it seems to me that you probably just want to subclass the Dictionary<TKey, TValue> type to add your own custom behavior. You can do this just once, in a general-purpose way, so that you can provide a delegate for each type you expect to have to use this way.
That would look something like this:
class KeyExtractorDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private readonly Func<TValue, TKey> _extractor;
public KeyExtractorDictionary(Func<TValue, TKey> extractor)
{
_extractor = extractor;
}
public void Add(TValue value)
{
Add(_extractor(value), value);
}
}
You would use it something like this:
class Data
{
public int Key { get; }
public string Name { get; }
public Data(int key, string name)
{
Key = key;
Name = name;
}
}
class Program
{
static void Main(string[] args)
{
KeyExtractorDictionary<int, Data> dictionary =
new KeyExtractorDictionary<int, Data>(d => d.Key)
{
new Data(1, "FooBar"),
new Data(2, "FizzBang")
};
}
}
(I used Data as the value type type, instead of T as you seem to have used in your question, to avoid confusing the type name with a generic type parameter.)
In this way, you only have to write the class once, regardless of how many different types you might want to use for this type of dictionary. You can then pass the class constructor the key extractor delegate appropriate for the current value type of the dictionary.
Note that doing it this way, you also can take advantage of C#'s collection initializer syntax. Since your new type has an Add() method that takes just the value for each dictionary entry, the compiler will translate a collection initializer into the correct calls to add each object to the dictionary.
This allows for a dictionary in which you can still retrieve objects solely by the key value (using a custom comparer would require an instance of the value type with the same key you're looking for), while still addressing the broader concerns of not having to specify the key explicitly when adding objects, and of generality and reuse.
You can try an extension method, which is less invasive:
public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
{
dictionary.Add(item.Key, item);
}
But to really do this correctly you also need an interface to protect you against types without the Key property:
public interface ItemWithKey<TKey>
{
TKey Key { get; }
}
public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
where T : ItemWithKey<TKey>
{
dictionary.Add(item.Key, item);
}
I don't have a compiler in my hands right now, I cannot test this code so minor errors may have slipped in. I hope you get the idea and usefulness if you have those cases a lot in your code. Otherwise, I'd advise to go with the ugly working code you already have.
You can use the ToDictionary() extension method to solve this issue. Here is a complete example that can be run in LINQPad.
void Main()
{
Dictionary<int, SomeComplextObject> dict = new List<SomeComplextObject>{
{new SomeComplextObject {Key = 1, Name = "FooBar"}},
{new SomeComplextObject {Key = 2, Name = "FizzBangr"}}
}.ToDictionary(k =>k.Key);
//Dump Dictionary to LINQPad's result window.
dict.Dump();
}
public class SomeComplextObject{
public int Key { get; set; }
public string Name {get;set;}
}
I would like to propose a different slightly different way of going about this, it's similar to #pid 's method but instead of an interface uses a linq expression. First built your list of objects, then use an extension method to add them to your dictionary in a single simple step. In my mind this is also a little more intuitive to read, your program would look like:
class Program
{
static void Main(string[] args)
{
List<SomeComplexObject> toAdd = new List<SomeComplexObject>() {
new SomeComplexObject(1,"FooBar"),
new SomeComplexObject(2,"FizzBang")
};
var dict = new Dictionary<int,SomeComplexObject>();
dict.AddByKey(toAdd, item => item.Key);
}
}
Where AddByKey is an extension method that uses linq to basically pass a reference to that property and would look like this:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
public static class DictionaryExtensions
{
/// <summary>
/// This extension method was built for when you want to add a list of items to a dictionary as the values, and you want to use one of those
/// items' properties as the key. It uses LINQ to check by property reference.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dict"></param>
/// <param name="targets"></param>
/// <param name="propertyToAdd"></param>
public static void AddByKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<TValue> targets, Expression<Func<TValue, TKey>> propertyToAdd)
{
MemberExpression expr = (MemberExpression)propertyToAdd.Body;
PropertyInfo prop = (PropertyInfo)expr.Member;
foreach (var target in targets)
{
var value = prop.GetValue(target);
if (!(value is TKey))
throw new Exception("Value type does not match the key type.");//shouldn't happen.
dict.Add((TKey)value, target);
}
}
}
And if you wanted to simplify the calling code even further, instead of returning void, you could have that extension method return the originally passed dictionary, and then your calling code could be collapsed to:
var dict = new Dictionary<int,SomeComplexObject>().AddByKey(toAdd, item => item.Key);
I have a common method which accepts any paramater as object
public static object Populate(object anyStuff)
{
}
I to send a List of a user defined class to this. and then de serialize it again in the method to loop through it. I am not sure how to accomplish.
You can use Generics.
Where you can create the generic method that handles different type of list and operates on them:
public static T Populate<T>(List<T> list){
//Do stuff
}
But if you are using talking about object (do note, not a good way you are trying to achieve):
public static object Populate(object anyStuff){
//Explicit typecast
List<string> value = anyStuff as List<string>();
}
If you want to know the usage of the first example with generic, here you can see the example
Usually you would create multiple overloads of Populate.
If I read your question correctly, you'd like something like this:
var properties = new Dictionary<string, object>
{
{"Name", "Bart"},
{"Date", new DateTime(2014,9,23)},
{"Age", 300}
}
var item = HelperClass.Populate(properies)
Console.WriteLine(item.Name); // should print "bart"
If this is what you want, you should look into the dynamic ExpandoObject.
(see http://blog.jorgef.net/2011/06/converting-any-object-to-dynamic.html )
public static dynamic Populate(IDictionary<string, object> anystuff)
{
IDictionary<string, object> expando = new ExpandoObject()
foreach(var key in anystuff)
{
expando[key] = anystuff[key];
}
return expando;
}
I have 2 data structures: Dictionary<string, string> and Multimap<string, string>.
Multimap is really just a Dictionary under the hood. I took must of the code from this question. Here's the class definition:
public class Multimap<TKey, TValue> : Dictionary<TKey, HashSet<TValue>>
{ ... }
Both data structures have a .Add(TKey key, TValue value) method.
I have a class that is responsible for populating these maps from certain files. I currently have the following two methods:
public Dictionary<string, string> PopulateDictionary(...)
{
Dictionary<string, string> returnDictionary = new Dictionary<string, string>();
...
foreach (...)
{
...
returnDictionary.Add(key, value);
}
return returnDictionary;
}
public Multimap<string, string> PopulateMultimap(...)
{
Multimap<string, string> returnMultimap = new Multimap<string, string>();
...
foreach (...)
{
...
returnMultimap.Add(key, value);
}
return returnMultimap;
}
As you can see, they're exactly the same, both around 25 lines long, and the only difference is their return type. What I am looking to do is condense this into one method.
My first attempt was to have the method
public Dictionary<string, object> PopulateGenericDictionary(...)
{ ... }
Where object was either string or HashSet<string>. But I didn't have much luck casting from Dictionary<string, object> to Multimap<string, string>.
Extracting the logic out of the methods is an option, but it's not great. Because of the foreach loops, there's always going to be some logic inside the two methods. You do end up with methods that are twice as small, but there's still two identical methods, which doesn't truly solve the problem.
This would be my ideal method structure:
public Dictionary<string, string> PopulateDictionary(...)
{
return MethodThatDoesAllTheLogic(...);
}
public Multimap<string, string> PopulateMultimap(...)
{
return MethodThatDoesAllTheLogic(...);
}
public ??? MethodThatDoesAllTheLogic(...)
{ ... }
I've been fiddling around with casting and generics, but I just can't get it to work. Any ideas?
Edit
I have used millimoose's solution. Here's my code now:
public Dictionary<string, string> GenerateDictionary(...)
{
Dictionary<string, string> returnMap = new Dictionary<string, string>();
PopulateDictionary(returnMap.Add, ...);
return returnMap;
}
public Multimap<string, string> GenerateMultimap(...)
{
Multimap<string, string> returnMap = new Multimap<string, string>();
PopulateDictionary(returnMap.Add, ...);
return returnMap;
}
private static void PopulateGenericDictionary(Action<string, string> addFunc, ...)
{
...
foreach (...)
{
addFunc(key, value);
}
}
Much cleaner!
To work around the lack of a common interface, you can invent one ad-hoc using a bunch of delegate type parameters:
void MethodThatDoesAllTheLogic(Action<string, string> addFunc)
{
// ...
addFunc(key, value);
// ...
}
public Dictionary<...> PopulateDictionary()
{
// ...
MethodThatDoesAllTheLogic(result.Add);
}
(Adding more parameters as necessary.)
I would avoid having the helper method create the actual collection at all; have it just populate an existing collection. That can be done much more effectively, since the Add method has the same signature in both cases. We can just use a delegate to accept the Add method:
public static void PopulateMapping<TKey, TValue>(Action<TKey, TValue> addMethod,
IEnumerable<TKey> data) //include other parameters needed to populate the data
{
foreach (var key in data)
{
addMethod(key, default(TValue));
}
}
Then it would be used like this:
public static Dictionary<string, string> PopulateDictionary()
{
Dictionary<string, string> output = new Dictionary<string, string>();
PopulateMapping<string, string>(output.Add, new string[] { "a" });
return output;
}
If you are only looking for an Add method, then both objects should share IDictionary. However, that Add method only uses objects. That is probably the closest that you can get without having to use generics in the method...but again you lose the benefits of generics at that point.
See if this approach will be useful:
The key is to make abstraction on creation of the object (Dictionary or Multimap) and aquiring the values - the two differences in the populating method.
public Dictionary<string, TValue> Populate<TValue>( Dictionary<string, TValue> returnDict, Func<SomeType, TValue> valueProvider)
{
string key = null;
...
foreach (...)
{
...
returnDict.Add(key, valueProvider(value));
}
return returnDict;
}
The example invocation is can be:
public void Test()
{
Populate(new Multimap<string, HashSet<string>>(), (t) => new HashSet<HashSet<string>>());
}
I'm not sure if the valueProvider delegate will be suited to your problem. Try to give more information about it.
If your inner logic is truly identical except for what type TValue is - and I mean word-for-word identical - then you could do something like:
IDictionary<string, TValue> MethodThatDoesAllTheLogic<TValue>(whatever)
{
// word for word-identical logic
}
I made the method take TValue as its only type parameter because that's the only difference (in the example you showed): both methods have string as the first type parameter.
ETA: This assumes that MultiMap implements IDictionary<K,V>. Since you said that it inherited from Dictionary<K,V> I assumed that it did.
in C# with generics you can require them to extend or implement a specific class in our case Dictionary, the following is how you might achieve that.
public T Populate<T>(string val) where T : Dictionary<string, string>, new()
{
T returnDict = new T();
returnDict.Add("key", "val");
return returnDict;
}
I need to add key/object pairs to a dictionary, but I of course need to first check if the key already exists otherwise I get a "key already exists in dictionary" error. The code below solves this but is clunky.
What is a more elegant way of doing this without making a string helper method like this?
using System;
using System.Collections.Generic;
namespace TestDictStringObject
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> currentViews = new Dictionary<string, object>();
StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view1");
StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view2");
StringHelpers.SafeDictionaryAdd(currentViews, "Employees", "view1");
StringHelpers.SafeDictionaryAdd(currentViews, "Reports", "view1");
foreach (KeyValuePair<string, object> pair in currentViews)
{
Console.WriteLine("{0} {1}", pair.Key, pair.Value);
}
Console.ReadLine();
}
}
public static class StringHelpers
{
public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, view);
}
else
{
dict[key] = view;
}
}
}
}
Just use the indexer - it will overwrite if it's already there, but it doesn't have to be there first:
Dictionary<string, object> currentViews = new Dictionary<string, object>();
currentViews["Customers"] = "view1";
currentViews["Customers"] = "view2";
currentViews["Employees"] = "view1";
currentViews["Reports"] = "view1";
Basically use Add if the existence of the key indicates a bug (so you want it to throw) and the indexer otherwise. (It's a bit like the difference between casting and using as for reference conversions.)
If you're using C# 3 and you have a distinct set of keys, you can make this even neater:
var currentViews = new Dictionary<string, object>()
{
{ "Customers", "view2" },
{ "Employees", "view1" },
{ "Reports", "view1" },
};
That won't work in your case though, as collection initializers always use Add which will throw on the second Customers entry.
What's wrong with...
dict[key] = view;
It'll automatically add the key if it's non-existent.
simply
dict[key] = view;
From the MSDN documentation of Dictionary.Item
The value associated with the
specified key. If the specified key is
not found, a get operation throws a
KeyNotFoundException, and a set
operation creates a new element with
the specified key.
My emphasis
As usual John Skeet gets in there with lighting speed with the right answer, but interestingly you could also have written your SafeAdd as an Extension Method on IDictionary.
public static void SafeAdd(this IDictionary<K, T>. dict, K key, T value)...
Although using the indexer is clearly the right answer for your specific problem, another more general answer to the problem of adding additional functionality to an existing type would be to define an extension method.
Obviously this isn't a particularly useful example, but something to bear in mind for the next time you find a real need:
public static class DictionaryExtensions
{
public static void SafeAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict,
TKey key, TValue value)
{
dict[key] = value;
}
}