3

this is somewhat the same question as I've asked some time ago: How to let a method accept two types of data as argument?

Yet the current situation differs.. a lot.

Take this:

public FormResourceSelector(Dictionary<string, Effect> resourceList, string type)

Alright, nothing wrong with it. Now I try to run this:

FormResourceSelector frs = new FormResourceSelector(AreaEffect.EFFECTS, "Area effect");
FormResourceSelector frs2 = new FormResourceSelector(DistanceEffect.EFFECTS, "Distance effect");

Both AreaEffect and DistanceEffect (custom classes) derive from Effect.

public class AreaEffect : Effect
{
    public static Dictionary<string, AreaEffect> EFFECTS = new Dictionary<string, AreaEffect>();
    ...
}

For some reason I get the following error while making the new FormResourceSelector instance:

Argument 1: cannot convert from 'System.Collections.Generic.Dictionary<string,SCreator.AreaEffect>' to 'System.Collections.Generic.Dictionary<string,SCreator.Effect>'  

at:

new FormResourceSelector(AreaEffect.EFFECTS, "Area effect");

I suspect the dictonary being a harass, but I don't really know how to fix this.

EDIT: Easiest would be to allow input of both Dictionary and Dictionary as resourceList in the first code snippet I've given.

Community
  • 1
  • 1
Tgys
  • 612
  • 1
  • 11
  • 21
  • Have you tried casting the input as (Effect)AreaEffect.EFFECTS ? – Corey May 21 '12 at 14:47
  • I need the "special" data stored in AreaEffect as well, not just the plain Effect data. It's hard to explain I'm afraid. – Tgys May 21 '12 at 14:54

4 Answers4

8

Why not make your class generic?

public class FormResourceSelector<T>
    where T : Effect
{
    public FormResourceSelector(Dictionary<string, T> resourceList, string type)
    {
    }
}
Ilia G
  • 10,043
  • 2
  • 40
  • 59
  • I'm afraid I have no idea what a "generic method" is. I've tried copy-pasting your code to begin with, but everything turns "errorish" in msvc: http://i.imgur.com/5KW8E.png . – Tgys May 21 '12 at 14:48
  • @SwDevMan81 Ah yes, I copy-pasted on from the question – Ilia G May 21 '12 at 15:02
  • Hehe, edited now ;). No errors after a few changes. Seems like it works! Thanks a lot, I'll investigate how those generic classes really work now. – Tgys May 21 '12 at 15:05
  • @Tgys yeah sorry, I didn't realize it was a class constructor. – Ilia G May 21 '12 at 15:07
2

Too large for a comment, so here is llia's answer updated to compile:

public class FormResourceSelector<T> where T : Effect
{
    // Constructor
    public FormResourceSelector(
       Dictionary<string, T> resourceList, string type) 
    {

    }
}
SwDevMan81
  • 48,814
  • 22
  • 151
  • 184
0

Consider the following:

public FormResourceSelector(Dictionary<string, Effect> resourceList, string type)
{
    resourceList.Add(new Effect());
}

Were you to pass a dictionary of derived types in:

var effects = new Dictionary<string, AreaEffect>();
new FormResourceSelector(effects, "");

You would have issues trying to set an Effect into what is really an AreaEffect, the compiler is stopping this from happening.

You could use generics in order to specify the type at compile time, as the other answer states.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
0

The concept at play here is know as variance - and you've run into the issue that Dictionary doesn't support covariance, as it's not read-only - this would be unsafe, for example:

IDictionary<string, object> myDict = new Dictionary<string, string>();
myDict["hello"] = 5; // not an string

See: IDictionary<TKey, TValue> in .NET 4 not covariant

Community
  • 1
  • 1
Dave Bish
  • 19,263
  • 7
  • 46
  • 63