1

I have a dictionary - the key of which is System.Type. I do not constrain the dictionary entries further; however, the dictionary is only exposed through a public class interface. I am mimicking an event system.

The System.Collections.Generic Dictionary looks like:

private Dictionary<Type, HashSet<Func<T>>> _eventResponseMap;

One of the methods that exposes the dictionary has the following signature:

public bool RegisterEventResponse<T>(Type eventType, Func<T> function)

However, I don't want the class user to be able to add any System.Type to the dictionary through this signature. Is there a way I can further constrain the Type parameter?

What I really want is something akin to (pseudo-code):

public bool RegisterEventResponse<T>(Type eventType, Func<T> function) where Type : ICustomEventType
Thomas
  • 6,291
  • 6
  • 40
  • 69
  • There's probably some garbage in the above code. If you could look past it, that'd be great. I'm shooting in the dark here, conceptually (will change per suggestions) – Thomas Dec 28 '16 at 23:35
  • 1
    Instead of `Type` you can use another generic type like `T2` and limit that to specific types you want. [This is been already answered here](http://stackoverflow.com/a/4834066/4767498) using policy pattern. this approach will give you compile time error if correct type is not used. easier approach would be to check types at runtime. – M.kazem Akhgary Dec 28 '16 at 23:37

2 Answers2

3

No, you won't get compile time safety on Type.

You could constrain T (or add a parameter) to ICustomEventType then use typeof in RegisterEventResponse to get the Type object you are looking for.

Alternatively just throw an exception:

if (!typeof(ICustomEventType).IsAssignableFrom(typeof(T))
{
    throw new ArgumentException("Type is not supported");
}
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • Didn't even think of throwing an error in this case. It'd be nice if compile time safety was achievable (don't know if that would even be feasible). One problem with the error piece is that it means the user would need to be more intimate with the implementation details -- which isn't a huge objection, but.. you know. – Thomas Dec 28 '16 at 23:42
  • 1
    @Thomas Only way to get compile time safety is to constrain an actual generic parameter (not `Type`) as in my middle paragraph. – BradleyDotNET Dec 28 '16 at 23:43
  • @Thomas or if you don't have a lot of different Types you can write different method overloads. how ever this may cause DRY problem. – M.kazem Akhgary Dec 28 '16 at 23:45
  • @BradleyDotNET yeah, that makes sense. I was looking at doing that; however, in this case (not in the OP), `T` isn't necessarily related to `ICustomEventType`. Oh, but wait. I could probably do that, anyway... Hm... *thinking*. Thanks, regardless! – Thomas Dec 28 '16 at 23:47
2

Why not change the signature of your method?

public bool RegisterEventResponse<TEvent, TReturn>(Func<TReturn> function)
    where TEvent: ICustomEventType
{
    _eventResponseMap[typeof(TEvent)] = function;  
}

Yes, you lose type inference but you gain type safety. Instead of writing RegisterEventResponse(typeof(CustomEvent), () => 1) you'd need to write RegisterEventResponse<CustomEvent, int>(() => 1).

InBetween
  • 32,319
  • 3
  • 50
  • 90
  • This I like. What would a call to this look like, roughly (using whatever garbage types you need to demonstrate)? – Thomas Dec 29 '16 at 00:05
  • 2
    Note that this what I meant by adding a parameter :) – BradleyDotNET Dec 29 '16 at 00:06
  • @BradleyDotNET do you mind if I accept this (per an answer to my above comment)? This is a very explicit example of what looks like what I need. Learning a lot, here. – Thomas Dec 29 '16 at 00:07
  • @Thomas Which answer to accept is totally up to you. IIRC the general guidance is "Whichever answer helped you the most". – BradleyDotNET Dec 29 '16 at 00:08