tags:

views:

459

answers:

3

Hello,

if you take a look at the following code, you will (hopefully) see what I am trying to archieve. Basically this code does:

  • A query for generic storag items (they store their type as string)
  • If the item is a subclass of SearchCriteria, create the correct instance
  • Add the instance to the list (SearchCriteria is superclass)

Not very elegant is, of course, the pseudo-switch case, which I would have to update for all different criteria I create.

So, my question, is there a "generic" way to create an instance which is strongly typed using a string as "source" for the type.

I know I can use Reflection to create an instance, but this is of type object, so I would not be able to add it to the list. Oh, just got an idea... Create object using reflection, cast it to supertype (SearchCrit), add to list. Real type should still be the "correct subtype" I hope...

Will try it, and update this post with results. Any better ideas?

Chris

   private IList<SearchCriteria> _searchCriteriaAll;
    public IList<SearchCriteria> SearchCriteriaAll
    {
        get
        {
            if (_searchCriteriaAll == null)
            {
                _searchCriteriaAll = new List<SearchCriteria>();
                var tN = typeof (SearchCriteria).ToString();
                foreach (var o in DataStorage.LinkedObjects)
                {
                    if (tN.StartsWith(o.TypeName))
                    {
                        if (o.TypeName == typeof(StringSearchCriteria).ToString())
                            _searchCriteriaAll.Add(new StringSearchCriteria(o));
                    }
                }
            }
            return _searchCriteriaAll;
        }
    }

EDIT:

Thanks for the tips, the "correct" way would definitly be the factory pattern. I will look into that. For now, I use this hack, because the subclasses are so small, I dont want a factory for each one.. (and this place is currently the only one with such a "fancy" feature)

   private IList<SearchCriteria> _searchCriteriaAll;
    public IList<SearchCriteria> SearchCriteriaAll
    {
        get
        {
            if (_searchCriteriaAll == null)
            {
                _searchCriteriaAll = new List<SearchCriteria>();
                var tN = typeof (SearchCriteria).ToString();
                foreach (var o in DataStorage.LinkedObjects)
                {
                    if (tN.StartsWith(o.TypeName))
                    {
                        var newO = Activator.CreateInstance(typeof(SearchCriteria).Assembly.FullName, o.TypeName);
                        var newCrit = newO.Unwrap() as SearchCriteria;
                        newCrit.DataStorage = o;
                        _searchCriteriaAll.Add(newCrit);
                    }
                }
            }
            return _searchCriteriaAll;
        }
    }
A: 

I'd say you're looking for the Factory Method Pattern.

There's a C# sample here - the first link explains the pattern better, the second is the right language for you.

Aaronaught
A: 

It's not entirely clear to me what you are trying to achieve, but you can create a Type from a string like this:

var t = Type.GetType(typeName);

If you want to examine whether it's a proper subtype, you can use the IsAssignableFrom method.

Mark Seemann
Close miss :-) No, I had the problem that I did not know how to cast the created type to the "real type" for the return list. But I now just cast to the supertype, calling functions on the object still calls the appropriate subtype implementation..
Christian
+2  A: 

Generics and reflection don't make good friends. A simpler approach here is to use the non-generic list interface:

_searchCriteriaAll = new List<SearchCriteria>();
IList list = (IList) _searchCriteriaAll;
...
Type type = typeof(SearchCriteria).Assembly.GetType(o.TypeName);
list.Add(Activator.CreateInstance(type));

(where o.TypeName includes the namespace information, but doesn't have to be assembly-qualified)

This is still runtime type-safe (it'll throw at runtime if it is wrong), and still adjusts the same list.

Note also that we only look inside Assembly directly via Assembly.GetType().

Marc Gravell