创建具有子类型限制的linq表达式

时间:2011-05-30 22:23:22

标签: linq c#-4.0 linq-to-objects

我有一个IEnumerable<MyBaseType>类型的列表,我正在尝试创建一个额外的where子句来检索列表中的特定项目。特定值仅存在于子类型MyFirstType和MySecondType上。不在MyBaseType上。

是否可以创建表达式......

MyList.Where(b => (b is MyFirstType || (b is MySecondType)) && b.SpecificValue == message.SpecificValue);

上面不起作用,因为b是MyBaseType类型,而那里不存在SpecificValue。另请注意,我确实有另一个没有SpecificValue的子类型MyThirdType。

做我想做的工作是什么......

foreach (dynamic u in MyList)
{
    if (u is MyFirstType || u is MySecondType)
    {
        if (u.SpecificValue == message.SpecificValue)
        {
            //Extracted code goes here
            break;
        }
    }
}

任何人都知道如何为上述场景创建一个linq表达式?

3 个答案:

答案 0 :(得分:3)

也许有一个更好的解决方案,但正如我所看到的,这可以运作得很好......如果你不介意表现。

那么,首先声明一个界面:

public interface IMySpecialType
{
   object SpecificValue {get; set;} //you didn't specify what type this is
   //all your other relevant properties which first and second types have in common
}

然后,使MyFirstType和MySecondType派生自此接口:

public class MyFirstType : MyBaseType, IMySpecialType
{
   //snipet
}

public class MyFirstType : MySecondType, IMySpecialType
{
   //snipet
}

然后,过滤并施放:

MyList
    .Where(b => (b is MyFirstType) || (b is MySecondType))
    .Cast<IMySpecialType>()
    .Where(b => b.SpecificValue == message.SpecificValue);
    //do something

答案 1 :(得分:1)

将代码直接转换为Linq where子句

string messageValue = "foo";
var result = baseList.Where(item =>
{
    dynamic c = item;
    if(item is MyFirstType || item is MySecondType)
    {
        if( c.SpecificValue == messageValue)
            return true;
    }
    return false;
});

这需要使用动态来测试类的类型,但 - 所以你也可以直接将项目转换为MyFirstTypeMySecondType

另一种方法是使用反射来检查属性是否存在,使用这种方法,只要他们拥有您感兴趣的属性,就不依赖于项目的实际类型:

string messageValue = "foo";
var result = baseList.Where( item => 
    {
        var prop =  item.GetType().GetProperty("SpecificValue");
        if (prop != null && prop.GetValue(item, null) == messageValue)
            return true;
        else return false;
    });

如果修改类层次结构是一个选项,您可以让MyFirstTypeMySecondType实现一个包含该属性的接口,那么您可以在Linq查询中使用OfType()

interface ISpecific
{
    string SpecificValue { get; set; }
}
class MyFirstType : MyBase, ISpecific
{
    public string SpecificValue { get; set; }
}
...
string messageValue = "foo";
var result = baseList.OfType<ISpecific>()
                     .Where(item => item.SpecificValue == messageValue);

答案 2 :(得分:0)

更简单的方法是创建一个界面来标记具有此属性的所有类 SpecificValue 。那是一场儿童游戏:

    static void Main(string[] args)
    {
        List<MyBaseType> MyList = new List<MyBaseType>();
        ISpecificValue message = new MyFirstType();
        MyList.OfType<ISpecificValue>().Where(b => b.SpecificValue == message.SpecificValue);
    }
}

class MyBaseType { }
interface ISpecificValue { string SpecificValue { get; set; } }
class MyFirstType : MyBaseType, ISpecificValue
{
    public string SpecificValue;
}
class MySecondType : MyBaseType, ISpecificValue
{
    public string SpecificValue;
}