Создание выражения linq с ограничением подтипа - PullRequest
0 голосов
/ 31 мая 2011

У меня есть этот список типа IEnumerable<MyBaseType>, для которого я пытаюсь создать дополнительное предложение where для получения определенного элемента в списке. Конкретное значение существует только для подтипа MyFirstType и MySecondType. Не в MyBaseType.

Можно ли создать выражение вида ...

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

Выше не работает, так как b имеет тип MyBaseType и SpecificValue там не существует. Также обратите внимание, что у меня есть другой подтип MyThirdType, который не имеет SpecificValue.

Что работает, делая то, что я хочу, это ...

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

У кого-нибудь есть идея, как создать выражение linq для приведенного выше сценария?

Ответы [ 3 ]

3 голосов
/ 31 мая 2011

Может быть, есть лучшее решение, но, на мой взгляд, это может сработать достаточно хорошо ... Если вы не против производительности.

Ну, тогда начните с объявления интерфейса:

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 голос
/ 31 мая 2011

Прямой перевод вашего кода в предложение Linq, где:

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;
});

Это потребует тестирования типа класса, хотя и с использованием динамического - так что вы можете также привести приведениедля элемента MyFirstType или MySecondType напрямую.

В качестве альтернативы можно использовать отражение, чтобы проверить, существует ли свойство, используя этот подход, вы не зависите от фактических типов ваших элементов, пока ониУ вас есть интересующее вас свойство:

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;
    });

Если вы можете изменить иерархию классов, вы можете MyFirstType или MySecondType реализовать интерфейс, который содержит свойство, тогда вы можете использовать OfType() в вашем запросе Linq:

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);
0 голосов
/ 31 мая 2011

Гораздо более простой способ сделать это - создать интерфейс для пометки всех ваших классов, имеющих это свойство 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;
}
...