System.NullReferenceException 在 LINQ 中
System.NullReferenceException in LINQ
基于之前写的 我现在尝试将多个图像从某个 subreddit 一次存储到本地目录中。我的问题是我无法让我的 LINQ 语句正常工作。我也不想下载缩略图,这就是为什么我查看 HTML 页面并发现我要检索的链接隐藏在 href
属性中的第 5 级:
(...)
Level 1: <div class="content">...</div>
Level 2: <div class="spacer">...</div>
Level 3: <div class="siteTable">...</div>
Level 4: <div class=" thing id-t3_6dj7qp odd link ">...</div>
Level 5: <a class="thumbnail may-blank outbound" href="href="http://i.imgur.com/jZ2ZAyk.jpg"">...</a>
这是我在行 '???' 中的最佳选择:
.Where(link => Directory.GetParent(link).Equals(@"http://i.imgur.com"))
可悲的是,它抛出一个 error 说明
Object reference not set to an instance of an object
好吧,现在我知道它为什么不起作用了,但我仍然不知道如何重写这一行,因为我对 Lambda 表达式还是很陌生。老实说,我真的不知道为什么我一开始就得到一个 System.NullReferenceException
而在下一行却没有。有什么不同?也许我在这个问题上的方法根本不是好的做法,所以请让我知道我如何才能继续下去。
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Net;
using HtmlAgilityPack;
namespace GetAllImages
{
class Program
{
static void Main(string[] args)
{
List<string> imageLinks = new List<string>();
// Specify Directory manually
string dirName = "Jessica Clements";
string rootPath = @"C:\Users\Stefan\Desktop";
string dirPath = Path.Combine(rootPath, dirName);
// Specify the subReddit manually
string subReddit = "r/Jessica_Clements";
string url = @"https://www.reddit.com/" + subReddit;
try
{
DirectoryInfo imageFolder = Directory.CreateDirectory(dirPath);
HtmlDocument document = new HtmlWeb().Load(url);
imageLinks = document.DocumentNode.Descendants("a")
.Select(element => element.GetAttributeValue("href", null))
.Where(???)
.Where(stringLink => !String.IsNullOrEmpty(stringLink))
.ToList();
foreach(string link in imageLinks)
{
using (WebClient _wc = new WebClient())
{
_wc.DownloadFileAsync(new Uri(link), Path.Combine(dirPath, Path.GetFileName(link)));
}
}
Console.WriteLine($"Files successfully saved in '{Path.GetFileName(dirPath)}'.");
}
catch(Exception e)
{
while(e != null)
{
Console.WriteLine(e.Message);
e = e.InnerException;
}
}
if(System.Diagnostics.Debugger.IsAttached)
{
Console.WriteLine("Press any key to continue . . .");
Console.ReadKey(true);
}
}
}
}
编辑:以防万一有人对此解决方案感兴趣,这就是我最终使用以下答案使其工作的方式:
HtmlDocument document = new HtmlWeb().Load(url);
imageLinks = document.DocumentNode.Descendants("a")
.Select(element => element.GetAttributeValue("href", null))
.Where(link => (link?.Contains(@"http://i.imgur.com") == true))
.Distinct()
.ToList();
鉴于此行抛出异常:
.Where(link => Directory.GetParent(link).Equals(@"http://i.imgur.com"))
我会确保 link
不为空并且 GetParent(link)
的结果也不为空。所以你可以这样做:
.Where(link => link != null && (Directory.GetParent(link)?.Equals(@"http://i.imgur.com") ?? false))
注意空检查和 GetParent()
之后的 ?.
。如果从 GetParent()
返回 null,这将停止执行该术语。它被称为 Null Conditional Operator 或 "Elvis Operator" 是因为它可以被看作是两只头发卷曲的眼睛。 ?? false
给出默认值,以防执行因空值而停止。
但是,如果您打算解析 HTML 代码,您绝对应该看看 Html Agility Pack (HAP).
如果您试图让所有链接都指向 http://i.imgur.com,您需要这样的东西
imageLinks = document.DocumentNode.Descendants("a")
.Select(element => element.GetAttributeValue("href", null))
.Where(link => link?.Contains(@"http://i.imgur.com") == true)
.ToList();
基于之前写的 href
属性中的第 5 级:
(...)
Level 1: <div class="content">...</div>
Level 2: <div class="spacer">...</div>
Level 3: <div class="siteTable">...</div>
Level 4: <div class=" thing id-t3_6dj7qp odd link ">...</div>
Level 5: <a class="thumbnail may-blank outbound" href="href="http://i.imgur.com/jZ2ZAyk.jpg"">...</a>
这是我在行 '???' 中的最佳选择:
.Where(link => Directory.GetParent(link).Equals(@"http://i.imgur.com"))
可悲的是,它抛出一个 error 说明
Object reference not set to an instance of an object
好吧,现在我知道它为什么不起作用了,但我仍然不知道如何重写这一行,因为我对 Lambda 表达式还是很陌生。老实说,我真的不知道为什么我一开始就得到一个 System.NullReferenceException
而在下一行却没有。有什么不同?也许我在这个问题上的方法根本不是好的做法,所以请让我知道我如何才能继续下去。
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Net;
using HtmlAgilityPack;
namespace GetAllImages
{
class Program
{
static void Main(string[] args)
{
List<string> imageLinks = new List<string>();
// Specify Directory manually
string dirName = "Jessica Clements";
string rootPath = @"C:\Users\Stefan\Desktop";
string dirPath = Path.Combine(rootPath, dirName);
// Specify the subReddit manually
string subReddit = "r/Jessica_Clements";
string url = @"https://www.reddit.com/" + subReddit;
try
{
DirectoryInfo imageFolder = Directory.CreateDirectory(dirPath);
HtmlDocument document = new HtmlWeb().Load(url);
imageLinks = document.DocumentNode.Descendants("a")
.Select(element => element.GetAttributeValue("href", null))
.Where(???)
.Where(stringLink => !String.IsNullOrEmpty(stringLink))
.ToList();
foreach(string link in imageLinks)
{
using (WebClient _wc = new WebClient())
{
_wc.DownloadFileAsync(new Uri(link), Path.Combine(dirPath, Path.GetFileName(link)));
}
}
Console.WriteLine($"Files successfully saved in '{Path.GetFileName(dirPath)}'.");
}
catch(Exception e)
{
while(e != null)
{
Console.WriteLine(e.Message);
e = e.InnerException;
}
}
if(System.Diagnostics.Debugger.IsAttached)
{
Console.WriteLine("Press any key to continue . . .");
Console.ReadKey(true);
}
}
}
}
编辑:以防万一有人对此解决方案感兴趣,这就是我最终使用以下答案使其工作的方式:
HtmlDocument document = new HtmlWeb().Load(url);
imageLinks = document.DocumentNode.Descendants("a")
.Select(element => element.GetAttributeValue("href", null))
.Where(link => (link?.Contains(@"http://i.imgur.com") == true))
.Distinct()
.ToList();
鉴于此行抛出异常:
.Where(link => Directory.GetParent(link).Equals(@"http://i.imgur.com"))
我会确保 link
不为空并且 GetParent(link)
的结果也不为空。所以你可以这样做:
.Where(link => link != null && (Directory.GetParent(link)?.Equals(@"http://i.imgur.com") ?? false))
注意空检查和 GetParent()
之后的 ?.
。如果从 GetParent()
返回 null,这将停止执行该术语。它被称为 Null Conditional Operator 或 "Elvis Operator" 是因为它可以被看作是两只头发卷曲的眼睛。 ?? false
给出默认值,以防执行因空值而停止。
但是,如果您打算解析 HTML 代码,您绝对应该看看 Html Agility Pack (HAP).
如果您试图让所有链接都指向 http://i.imgur.com,您需要这样的东西
imageLinks = document.DocumentNode.Descendants("a")
.Select(element => element.GetAttributeValue("href", null))
.Where(link => link?.Contains(@"http://i.imgur.com") == true)
.ToList();