Reputation: 7005
I have a set of overloads for a get
function. Each one have a different input type but basically the same signature schema (as follow):
string GetPropertyValue(int propId, string defaultValue)
bool GetPropertyValue(int propId, bool defaultValue)
int GetPropertyValue(int propId, int defaultValue)
IEnumerable<string> GetPropertyValue(int propId, IEnumerable<string> defaultValues)
IEnumerable<bool> GetPropertyValue(int propId, IEnumerable<bool> defaultValues)
IEnumerable<int> GetPropertyValue(int propId, IEnumerable<int> defaultValues)
I am working on simplifying the API into a single generic method (as follow):
T GetPropertyValue<T>(int propId , T defaultValue)
To implement such method, I tried to switch on the type on the default value using a dictionary (inspired by this answer):
var actionDico = new Dictionary<Type, System.Action>
{
/* since the type of `defaultValue` is `T`, I cannot use `(bool)defaultValue` for example
therefore casting to (object) before to escape Cast operator restriction.
Will not fail as the key of the dictionary is a matching type */
{typeof(bool), () => dob.GetPropertyValue(propId, (bool)(object)defaultValue)},
{typeof(int), () => dob.GetPropertyValue(propId, (int)(object)defaultValue)},
{typeof(string), () => dob.GetPropertyValue(propId, (string)(object)defaultValue)}
}
With concrete types, the previous implementation is perfectly fine (at least in my case). The call will be done using actionDico[typeof(T)]();
.
Having the following within the dictionary is fine:
{typeof(IEnumerable<int>), () => dob.GetPropertyValue(propId, (IEnumerable<int>)(object)defaultValue)},
But the call is usually done using an object which implement IEnumerable<int>
(like List<int>
). In such case calling actionDico[typeof(T)]();
is looking for List<int>
within the keys collection, not IEnumerable<int>
.
I am trying to avoid reflection (and will keep it as last resort). Is there a way similar to Type.IsAssignableFrom(Type)
method for interfaces? In other words, I want to check wether the provided type implements IEnumerable<int>
rather than being it.
Upvotes: 1
Views: 570
Reputation: 1500225
You can't look the type up in the dictionary that way. You'll have to loop through the key-value pairs:
Type targetType = defaultValue.GetType();
foreach (var pair in dictionary)
{
if (pair.Key.IsAssignableFrom(targetType))
{
// Use pair.Value
}
}
However, at this point you've effectively just got a List<Tuple<Type, Action>>
rather than a dictionary, in terms of how you're using it... So you could instead use:
List<Tuple<Type, Action>> actions = new List<Tuple<Type, Action>>
{
Tuple.Create(typeof(bool), () => dob.GetPropertyValue(propId, (bool) (object)defaultValue),
Tuple.Create(typeof(int), () => dob.GetPropertyValue(propId, (int) (object)defaultValue),
// etc
};
... and then just use Item1
and Item2
in the loop earlier.
Upvotes: 1
Reputation: 10229
You can use the as operator
var isEnumerable = defaultValue as IEnumerable;
if (isEnumerable != null)
{
}
Upvotes: 0