我已经回顾了类似问题的其他答案,但无法找到我想要的内容。我有一个Superclass类型的字典,可以存储2个子类中的任何一个的实例。我需要能够访问其中一个子类的成员。我无法弄清楚如何将LINQ查询转换为子类来访问它。这就是我所拥有的。
class VirtualFabric
{ Dictionary<string, SANSwitch} MemberSwitches = new Dictionary<string, SANSwitch>();
class SANSwitch
{
string SwitchWWN {get; set; }
Dictionary<int, VirtualFabric> VirtualFabrics = new Dictionary<int, VirtualFabric>();
}
class CiscoSwitch : SanSwitch {}
class BrocadeSwitch : SanSwitch
{
public Dictionary<int, string> VirtualWWNList = new Dictionary<int, string>();
public bool HasWWN(string wwn)
{
if (wwn.StartsWith("55")) { return this.VirtualWWNList.Values.Contains(wwn); }
else { return this.SwitchWWPN.Contains(wwn); }
}
}
因此,VirtualFabric中的MemberSwitches可以存储CiscoSwitch或BrocadeSwitch的实例。我试图这样做:
List<SwitchPort> isls = this.ISLs.SelectMany(p => p.Value.Where(i => i is FCPort)).ToList();
// set up the ISLs
// if the remote switch port list already contains a port, then that switch log has been processed
// so do nothing
foreach (SwitchPort p in isls)
{
var bs = this.VirtualFabricList.SelectMany(t => t.Value.MemberSwitches.Values.Where
(s => s.Value.HasWWN(p.RemoteSwitchWWPN)));
// do something with any results
} // foreach
SelectMany未编译,因为HasWWN()是在BrocadeSwitch中定义的,而不是在SANSwitch中定义的。我可以把它移到SANSwitch,但不想。我也可以在Brocade类型的MemberSwitches中获取所有开关或迭代并将它们声明为Brocade然后搜索该列表,但我想知道是否有一种方法可以在LINQ语句中进行转换。我见过选择某种类型的例子,但这不是我想要的。
答案 0 :(得分:0)
这是一个派生另一个类的类:
public class Class1 { }
public class Class2 : Class1 {
public List<Class2> Twos { get { return new List<Class2>(); } }
}
以下是如何施放:
var c1 = new Class2();
var c2 = new Class2();
var l = new List<Class2> { c1, c2 };
var ints = l.SelectMany( x => x.Twos ).Cast<Class1>();
或者只是投射枚举器而不是像这样投射每个对象:
var ints = l.SelectMany( x => x.Twos ) as IEnumerable<Class1>;
由于Class2
派生Class1
,您可以进行投射。但是,如果您尝试从Class1
投射到Class2
,则会失败,因为Class2
更具体。
修改强>
你有这个lambda:
var bs = this.VirtualFabricList.SelectMany(t => t.Value.MemberSwitches.Values.Where
(s => s.Value.HasWWN(p.RemoteSwitchWWPN)));
MemberSwithches.Values
将返回SANSwitch
,然后您尝试调用s.Value.HasWWN
方法,但CiscoSwitch
没有HasWWN
方法。你不能这样做。你需要这样做:
var bs = this.VirtualFabricList.SelectMany( t => t.Value.MemberSwitches.Values
.Where( s => s.Value is BrodcadeSwitch ) ).Cast<BrodcadeSwitch>()
.Where( s => s.HasWWN( p.RemoteSwitchWWPN ) );
答案 1 :(得分:0)
您忘了描述VirtualFabricList类型。
从你的linq语句我收集到一个VirtualFabricList不是VirtualFabric对象的序列,因为VirtualFabricList中的每个“t”都有一个属性Value
,这个属性不在你的VirtualFabric类中。
然而,从你的其他linq我收集到每个t.Value是一个VirtualFabric。此外,每个t.Value都有一个属性MemberSwitches,它是一个包含SANSwitch对象的字典。
您只需要此字典中的某些对象:只有字典中的那些SANSwitch是BrocadeSwitch对象。甚至不是所有的BrocadeSwitch,只有HasWwn(...)返回true的那些。
您的问题是您检查了SANSwitches字典中HasWWN的所有元素,而您只能检查BrocadeSwitch字符。为此,您可以使用Enumerable.OfType
小步骤:
IEnumerable<VirtualFabric> virtualFabrics = this.VirtualFabricList
.Select(t => t.Value>);
IEnumerable<Dictionary<string, SANSwitch>> dictionaries = virtualFabrics
.Select(fabric => fabric.MemberSwitches);
IEnumerable<SanSwitch> sanSwitches = dictionaries
.SelectMany(dictionary => dictionary.Values);
注意:如果我对您的VirtualFacbricList的猜测不正确,请使用您自己的语句来获取一系列SanSwitch对象。从这个序列中你可以得到BrocadeSwitches:
IEnumerable<SanSwitch> sanSwitches = ...
IEnumerable<BrocadeSwitch> brocadeSwitches = sanSwitches.OfType<BrocadeSwitch>();
IEnumerable<BrocadeSwitch> switchesWithWWN = brocadeSwitches
.Select(brocadeSwitch => brocadeSwitch.HasWWN(...)
所以关键功能是 Enumerable.OfType
这些小步骤可帮助您检查每个linq语句是否包含您期望的项目。它不会减慢你的进程,因为延迟执行这些语句直到你的ToList()才会被执行。
当然,如果可读性和调试能力不是优先级列表中最高的,那么您可以将这些语句放入一个大的linq语句中。