简体   繁体   中英

C# Generic Class field possible

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> IList<? extends Object> .

Thanks!

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


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);
    }
}

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. ie 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>

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