在包括接口的类型之间切换 [英] Switch between types including interfaces

查看:99
本文介绍了在包括接口的类型之间切换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于 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 而不是它。

解决方案

你不能以这种方式在字典中查找类型。您必须遍历键值对:

 类型t​​argetType = 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆