对象的Linq - 选择第一个对象

12

我对linq几乎一无所知。

我正在做这个:

var apps = from app in Process.GetProcesses()
    where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
    select app;

这让我得到了所有符合该标准的正在运行的进程。

但是我不知道如何获得第一个进程。我在网上找到的示例似乎暗示着我必须这样做

var matchedApp = (from app in Process.GetProcesses()
    where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
    select app).First();

这让我感觉有点丑陋,而且如果没有匹配的进程会抛出异常。有更好的方法吗?

更新

实际上,我正在尝试找到第一个匹配的项目,并在其上调用SetForegroundWindow

我想出了这个解决方案,它也让我感觉很丑陋和糟糕,但比上面的方法好。有什么想法吗?

var unused = from app in Process.GetProcesses()
    where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
    select SetForegroundWindow( app.MainWindowHandle ); // side-effects in linq-query is technically bad I guess
3个回答

20

@FryHard,FirstOrDefault将起作用,但请记住如果没有找到任何项,它会返回null。此代码未经测试,但应接近您想要的内容:

var app = Process.GetProcesses().FirstOrDefault(p => p.ProcessName.Contains("MyAppName") && p.MainWindowHandle != IntPtr.Zero);

if (app == null)
    return;

SetForegroundWindow(app.MainWindowHandle);

你怎么将它作为查询而不是扩展方法输入? - Quintin Par
2
@Quintin,FirstOrDefault没有“关键字”语法-您必须使用扩展方法。 - Matt Hamilton
1
你可以使用 (query).FirstOrDefault(),但我认为扩展方法语法更易读。 - Jim Deville
我从来没有理解为什么这么多人更喜欢使用SQL语法而不是方法语法。太神奇了。 SQL的美妙之处在于它的速度,而不是它的语法!从语法上讲,SQL是我一生中见过的最可怕的东西。Quintin,虽然已经过去将近三年了,如果你还没有开始使用扩展方法,请开始使用吧。 - vbullinger

2
不要像ICR所说的那样使用Count()Count()会遍历整个IEnumerable以确定它有多少项。在这种情况下,性能损失可能微不足道,因为没有太多的进程,但这是一个不好的习惯。只有在查询仅对结果数感兴趣时才使用Count()。几乎从来不应该使用Count
FryHard的回答存在几个问题。首先,由于延迟执行,您将需要执行两次LINQ查询,一次获取结果数量,一次获取FirstOrDefault。其次,在检查计数后没有任何理由使用FirstOrDefault。由于它可以返回null,因此您永远不应该在未检查null的情况下使用它。可以使用apps.First().MainWindowHandle或:
var app = apps.FirstOrDefault();

if (app != null)
    SetForegroundWindow(app.MainWindowHandle);

这就是为什么最好的解决方案是Mark的,毫无疑问。这是使用LINQ获取所需内容最高效和稳定的方式。

0
假设在你的第一个例子中,apps是一个IEnumerable,你可以利用.Count和.FirstOrDefault属性来获取你想要传递给SetForegroundWindow的单个项。
var apps = from app in Process.GetProcesses()
where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
select app;

if (apps.Count > 0)
{
    SetForegroundWindow(apps.FirstOrDefault().MainWindowHandle );
}

1
正如其他地方所述,这会取消LINQ的优势(延迟执行),而且FirstOrDefault与Count重复。 - Jim Deville

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接