在包括接口的类型之间切换 [英] Switch between types including interfaces
问题描述
对于 get
函数,我有一组重载。每个人都有不同的输入类型,但基本上是相同的签名架构(如下):
$ p $ 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)
我正致力于将API简化为单一通用方法(如下):
T GetPropertyValue< T>(int propId,T defaultValue)
$为了实现这样的方法,我尝试使用字典( /stackoverflow.com/a/298994/837623\">受此答案所启发):
var actionDico = new Dictionary< Type,System.Action>
{
/ *因为`defaultValue`的类型是`T`,所以我不能使用`(bool)defaultValue`例如
,因此在转义之前先转换为(object) 。
不会失败,因为字典的键是匹配类型* /
{typeof(bool),()=> dob.GetPropertyValue(propId,(bool)(object)defaultValue)},
{typeof(int),()=> dob.GetPropertyValue(propId,(int)(object)defaultValue)},
{typeof(string),()=> dob.GetPropertyValue(propId,(string)(object)defaultValue)}
}
具体类型,以前的实现是完全正常的(至少在我的情况下)。该调用将使用 actionDico [typeof(T)]();
。
完成。字典很好:
{typeof(IEnumerable< int>),()=> dob.GetPropertyValue(propId,(IEnumerable< int>)(object)defaultValue)},
调用通常使用实现 IEnumerable< int>
(如 List< int>
)的对象完成。在这种情况下,调用 actionDico [typeof(T)]();
在键内寻找 List< int>
我试图避免反思(并将保留它作为最后的手段)。 )。有没有类似于 Type.IsAssignableFrom(Type)
方法的接口方法?换句话说,我想检查提供的类型实现 IEnumerable
而不是它。
解决方案你不能以这种方式在字典中查找类型。您必须遍历键值对:
类型targetType = defaultValue.GetType();
foreach(字典中的var对)
{
if(pair.Key.IsAssignableFrom(targetType))
{
//使用pair.Value
}
}
然而,在这一点上,您已经得到了列出< Tuple< Type,Action>>< / code>< / code>< / code> b
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
};
...然后只需使用 Item1
和 Item2
in循环更早。
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.
解决方案 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.
这篇关于在包括接口的类型之间切换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!