好的,我会尝试尽可能地解释我的问题,从下面的代码片段我将tempURLTestedVsCaptured传递给我的方法CheckForDuplicates_capturedUrls。
此方法将检查是否存在重复项,如果没有,则会将URL(包含在我的URL对象中)添加到新的URL对象中。完成后,它会将原始tempURL设置为新对象的引用。
我有tempURLTestedVsCaptured的问题是没有得到新的引用。如果我观察tempURL,它在方法结束时具有正确的值,当它跳回到Crawl方法时,tempURLTestedVsCaptured已返回到原始值。
如果我更改了tempURL,例如添加了一个URL,则会反映出这些更改。
如果我这样做:
tempURLs = new URLs();
tempURLs = processedURLs;
它不会接受改变。在我的学习中,我显然遗漏了一些非常有趣的东西,但我不能指责它。
private void CheckForDuplicates_capturedUrls(URLs tempURLs)
{
URLs unprocessedURLs = (URLs)tempURLs;
URLs processedURLs = new URLs();
foreach (URL url in unprocessedURLs)
{
if (!crawlContext.capturedUrls.ContainsURL(url))
{
processedURLs.AddURL(url);
}
}
tempURLs = new URLs();
tempURLs = processedURLs;
}
private void Crawl(WebScraper_Context crawlContext)
{
URLs tempURLTestedVsVisited = new URLs();
URLs tempURLTestedVsCaptured = new URLs();
while (crawlContext.unVistedURLs.Count() != 0) //While we have URLS we not visited, continue
{
foreach (URL url in crawlContext.unVistedURLs)
{
// If we not visted the page yet
if (!crawlContext.vistedURLs.ContainsURL(url)) // Vist the URL if there is one
{
crawlContext.vistedURLs.AddURL(url);
LoadPage(url.url);
doc = GetSubSetXPath(doc, crawlContext.xPath);
}
if (doc != null)
{
crawlContext.scrapedUrls = ScrapeURLS();
crawlContext.scrapedUrls = GetLocalUrls(crawlContext.scrapedUrls);
// Cache the URLS into, so we can check if we seen them before
foreach (URL newURL in crawlContext.scrapedUrls)
{
if (!tempURLTestedVsVisited.ContainsURL(newURL))
{
tempURLTestedVsVisited.AddURL(newURL);
tempURLTestedVsCaptured.AddURL(newURL);
}
else
{
System.Windows.Forms.MessageBox.Show("Duplicate URL found in scraped URLS");
}
}
**this.CheckForDuplicates_capturedUrls(tempURLTestedVsCaptured);**
foreach (URL newURL in crawlContext.scrapedUrls)
{
if (tempURLTestedVsVisited.ContainsURL(newURL) && tempURLTestedVsCaptured.ContainsURL(newURL))
{
crawlContext.newURLs.AddURL(newURL);
crawlContext.capturedUrls.AddURL(newURL);
}
}
}
}
crawlContext.unVistedURLs = new URLs(); crawlContext.unVistedURLs = crawlContext.newURLs;
crawlContext.newURLs = new URLs();
}
if (RequestStop == true)
{
RequestStop = false;
}
System.Windows.Forms.MessageBox.Show("Complete");
}
Ok T. Kiley完全解释了我的问题以及我为什么会这样做。 我没有返回URLS的原因,我正在做一个毫无意义的演员,因为方法签名计划是:
private void CheckForDuplicates_capturedUrls(object tempURLs).
该方法将用作线程启动“DuplicateCheckerB = new Thread(this.CheckForDuplicates_capturedUrls);”和“DuplicateCheckerA.Start(tempURLTestedVsVisited);”我最初认为我的问题归结为线程,所以我剥离了它在调试过程中。
现在,如果我要将其传递给线程,我是否会认为我必须修改实际对象以删除URL?
答案 0 :(得分:3)
您没有通过引用传递方法参数:
private void CheckForDuplicates_capturedUrls(ref URLs tempURLs) {...}
并称之为:
CheckForDuplicates_capturedUrls(ref tempURLTestedVsCaptured);
或者, 最好 ,只需返回一个新列表:
private URLs CheckForDuplicates_capturedUrls(URLs tempURLs) {
URLs result = new URLs();
// process tempURLs, storing the result
return result;
}
并像这样使用它:
tempURLTestedVsCaptured = CheckForDuplicates_capturedUrls(tempURLTestedVsCaptured);
答案 1 :(得分:2)
您的代码存在一些问题,但是首先需要了解第一种方法的问题,首先需要了解传递引用和传递值之间的区别。这个概念在C#和Java(比C ++ [imo])这样的语言中更加混乱,因为它看起来像是通过引用传递,实际上它(几乎)总是通过值传递。
基本上,当函数通过值时,参数的值将复制到函数中。显然,如果你这样做,任何修改都将丢失。
另一方面,通过引用传递,只是告诉函数在哪里查看,因此将保留修改。
C#按值传递,但您传递的值是指针
这在实践中意味着,你将指针传递给你的tempUrls。如果你要修改这个指针指向的东西,你会修改你传入的东西。
但是,你在方法中做了什么:
tempURLs = processedURLs;
积分会变成新事物。我们通过值传递地址,因此更改地址将不会执行任何操作。来电者仍在寻找旧位置。
您可以使用ref
关键字解决此问题,但在此方法中,返回新的tempUrls可能会更好
其他问题 您的代码还有其他一些问题:
new
答案 2 :(得分:1)
在C#中,参数是按值传递的。这意味着您在所调用的方法中获得了引用的副本。您对该副本所做的任何更改都不会影响该方法调用之外的其他引用。通过对参数使用ref
关键字,您可以对原始引用进行更改,但不要这样做。从方法中返回新值是更好的方法。
private URLs CheckForDuplicates_capturedUrls(URLs tempURLs) {...}
答案 3 :(得分:1)
您可以使用引用参数修复此问题,但更好的设计是按照以下模式返回新列表:
tempUrls = CheckForDuplicates_capturedUrls(URLs tempURLs)
private URLs CheckForDuplicates_capturedUrls(URLs tempURLs)
{
//It's not clear what options your URLs type has, but based on
// your example use, it looks like you might be inheriting List<url>
// or implementing IList. This code makes that assumption
return tempURLs.Where(url => !crawlContext.capturedUrls.ContainsURL(url)).ToList();
}
我们甚至将代码缩减为单行代码:)
原始代码不起作用,因为.Net按值传递对函数的引用。这意味着该函数获取引用同一对象的引用,但仍然只是一个副本。该函数可以更改对象中的属性,或调用它的方法,这些更改对于函数的调用者来说是显而易见的。但是,如果函数尝试直接对变量本身进行赋值,则只会更改副本。
答案 4 :(得分:-3)
在C#中,对象通过引用传递。但是,当您提供一个方法对象时,它会生成指针的副本(引用是一个安全指针),然后将其提供给该函数。
将'ref'添加到方法调用中,您将传递原始引用。
private void CheckForDuplicates_capturedUrls( ref 网址tempURLs)