使用子类型限制创建linq表达式
我有一个类型为使用子类型限制创建linq表达式,linq,c#-4.0,linq-to-objects,Linq,C# 4.0,Linq To Objects,我有一个类型为IEnumerable的列表,我试图为它创建一个额外的where子句来检索列表中的特定项。特定值仅存在于子类型MyFirstType和MySecondType上。不在MyBaseType上 有没有可能创建一个类似于 MyList.Where(b => (b is MyFirstType || (b is MySecondType)) && b.SpecificValue == message.SpecificValue); 由于b的类型为MyBaseType
IEnumerable
的列表,我试图为它创建一个额外的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表达式吗?将代码直接翻译成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;
});
这将需要通过使用dynamic测试类的类型,所以您可以直接将项转换为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
实现一个保存属性的接口,然后您可以在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);
接口是特定的
{
字符串特定值{get;set;}
}
类MyFirstType:MyBase,IsSpecific
{
公共字符串SpecificValue{get;set;}
}
...
字符串messageValue=“foo”;
var result=baseList.OfType()
.其中(item=>item.SpecificValue==messageValue);
将代码直接翻译为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;
});
这将需要通过使用dynamic测试类的类型,所以您可以直接将项转换为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
实现一个保存属性的接口,然后您可以在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);
接口是特定的
{
字符串特定值{get;set;}
}
类MyFirstType:MyBase,IsSpecific
{
公共字符串SpecificValue{get;set;}
}
...
字符串messageValue=“foo”;
var result=baseList.OfType()
.其中(item=>item.SpecificValue==messageValue);
也许有更好的解决方案,但在我看来,这可能足够有效。。。如果你不介意表演的话
那么,首先声明一个接口:
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
}
public class MyFirstType : MyBaseType, IMySpecialType
{
//snipet
}
public class MyFirstType : MySecondType, IMySpecialType
{
//snipet
}
然后,使MyFirstType和MySecondType从此接口派生:
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
}
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
MyList
。其中(b=>(b是MyFirstType)| |(b是MySecondType))
.Cast()
.其中(b=>b.SpecificValue==message.SpecificValue);
//做点什么
也许有更好的解决方案,但在我看来,这可能足够有效。。。如果你不介意表演的话
那么,首先声明一个接口:
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
}
public class MyFirstType : MyBaseType, IMySpecialType
{
//snipet
}
public class MyFirstType : MySecondType, IMySpecialType
{
//snipet
}
然后,使MyFirstType和MySecondType从此接口派生:
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
}
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
MyList
。其中(b=>(b是MyFirstType)| |(b是MySecondType))
.Cast()
.其中(b=>b.SpecificValue==message.SpecificValue);
//做点什么
更简单的方法是创建一个接口来标记所有具有此属性的类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;
}
static void Main(字符串[]args)
{
List MyList=新列表();
isSpecificValue消息=新的MyFirstType();
MyList.OfType()。其中(b=>b.SpecificValue==message.SpecificValue);
}
}
类MyBaseType{}
接口isSpecificValue{string SpecificValue{get;set;}}
类MyFirstType:MyBaseType,isSpecificValue
{
公共字符串特定值;
}
类MySecondType:MyBaseType,isSpecificValue
{
公共字符串特定值;
}
更简单的方法是创建一个接口来标记所有具有此属性的类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;
}
static void Main(字符串[]args)
{
List MyList=新列表();
isSpecificValue消息=新的MyFirstType();
MyList.OfType()。其中(b=>b.SpecificValue==message.SpecificValue);
}
}
类MyBaseType{}
接口isSpecificValue{string SpecificValue{get;set;}}
类MyFirstType:MyBaseType,isSpecificValue
{
公共字符串特定值;
}
类MySecondType:MyBaseType,isSpecificValue
{
公共字符串特定值;
}
我实际上选择了第一个版本的dynamic。谢谢实际上,我倾向于使用dynamic的第一个版本。谢谢哎呀!我没有注意到弗朗西斯科的类似回答。我更喜欢我的,因为内置的类型
对我来说似乎比Where
和Cast
的奇怪组合更优雅,其中实现类型MyFirstType
和MySecondType
是硬编码的。注意到你的答案与Francisco类似。是的,它确实很简单,但我不想再介绍另一个界面。我非常尊重这个愿望。尽管如此,我还是会毫不犹豫地这么做。整个.Net框架就是这样构思的:尽可能抽象,接口而不是类。。。创建这个新的单行程序接口的成本可以忽略不计,接口的用途也不难理解(因为有一个不言自明的名称),而且它还提高了代码的可维护性。如果将来会出现具有SpecificValue属性的其他类,则不必修改代码来硬编码这个新类