Reputation: 23
I am new to C# (Java developer), I want to have a class field that is a generic list, actually it is a dictionary of lists:
protected IDictionary<String, IList<Object>> filters;
I have code that sets
public void SetFilters(String key, params Object[] values) {
if (key == null || values == null) {
throw new ArgumentNullException("Must have filter name and values.");
}
if (filters == null) filters = new Dictionary<String, IList<Object>>();
IList<Object> fvalues = values.ToList();
filters.Add(key, fvalues);
}
But when my code tries to retrieve and cast the IList<Object>
back to IList<String>
or IList<int>
I get an InvalidCastException.
I thought I would make the list generic:
protected IDictionary<String, IList<T>> filters; //does not complile
protected IDictionary<String, IList<T>> filters where T: Object;//does not compile either
I cannot make the class generic since the dictionary will have lists of Strings
or int
. In Java, Integer
and Strings
are all Objects
, so this was not an issue with IList<? extends Object>
.
Thanks!
Upvotes: 1
Views: 243
Reputation: 4059
In order to avoid the error casting, you need to create a typed list in the first place. To do that you should use a generic.
For the dictionary item type, you can use IList or object but you will need to store a strongly typed list as the item value.
If you make SetFilters a generic method, then it can make a properly typed list to store in the dictionary. I included a GetFilters method that returns the list that matches the key. i.e. values.ToList() will create a List<T>
public class FilterManager
{
protected IDictionary<String, IList> filters = new Dictionary<string, IList>();
public void SetFilters<T>(String key, params T[] values)
{
if (key == null || values == null)
{
throw new ArgumentNullException("Must have filter name and values.");
}
IList fvalues = values.ToList();
filters.Add(key, fvalues);
}
public IList<T> GetFilters<T>(string key)
{
return (IList<T>)filters[key];
}
}
Call it like this
var filterManager = new FilterManager();
filterManager.SetFilters("MyIntegerFilters", 3, 4, 5);
filterManager.SetFilters("MyStringFilters", "A", "B", "C");
var intFilters = filterManager.GetFilters<int>("MyIntegerFilters");
var stringFilters = filterManager.GetFilters<string>("MyStringFilters");
You will get an exception if you call
var filters = filterManager.GetFilters<int>("MyStringFilters");
because it will try to convert a List<string>
to a List<int>
Upvotes: 0
Reputation: 22339
You could use System.Collection.IList
, similar to this:
public class Foo
{
public IDictionary<String, IList> filters;
public void SetFilters(String key, params object[] values)
{
if (key == null || values == null)
{
throw new ArgumentNullException("Must have filter name and values.");
}
if (filters == null)
{
filters = new Dictionary<String, IList>();
}
IList fvalues = values.ToList();
filters.Add(key, fvalues);
}
}
You could then use it like this:
var foo = new Foo();
foo.SetFilters("Key1", 1,2,3);
foo.SetFilters("Key2", "a","b","c");
foo.SetFilters("Key3", new {a = 1, b = 2}, new {c = 1, d = 2});
You still have then the issue of casting back each list type into the expected type when accessing and using it.
DEMO - Using IList
Upvotes: 2
Reputation: 281
Does it help? I created a new generic class.
internal class Program
{
private class Reed<T>
{
private IDictionary<String, IList<T>> filters;
public void SetFilters(String key, params T[] values)
{
if (key == null || values == null)
{
throw new ArgumentNullException("Must have filter name and values.");
}
if (filters == null)
filters = new Dictionary<String, IList<T>>();
IList<T> fvalues = values.ToList();
filters.Add(key, fvalues);
}
}
private static void Main(string[] args)
{
var r1 = new Reed<string>();
r1.SetFilters("test", "one", "two", "three");
var r2 = new Reed<int>();
r2.SetFilters("test", 1, 2, 3);
}
}
Upvotes: 0