似乎每次我去写一个递归函数我最终都会返回void并使用ref参数。
我更愿意编写一个只返回结果列表的函数。
如果答案非常简单,请道歉 - 由于某些原因,它不包括我。
这是我现在的代码:
public static void GetResrouces(string startURL, ref List<XDocument> result)
{
var doc = XDocument.Parse(GetXml(startURL)); // GetXml ommitted - returns xml string
var xs = new XmlSerializer(typeof(resourceList));
var rdr = doc.CreateReader();
if (xs.CanDeserialize(rdr))
{
var rl = (resourceList)xs.Deserialize(doc.CreateReader());
foreach (var item in rl.resourceURL)
{
GetResrouces(startURL + item.location, ref result);
}
}
else
{
result.Add(doc);
}
}
public partial class resourceList
{
private resourceListResourceURL[] resourceURLField;
private string locationField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("resourceURL")]
public resourceListResourceURL[] resourceURL
{
get
{
return this.resourceURLField;
}
set
{
this.resourceURLField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlAttributeAttribute(DataType = "anyURI")]
public string location
{
get
{
return this.locationField;
}
set
{
this.locationField = value;
}
}
}
我想知道它是否可以重写原型:
public static List<XDocument> GetResources(string startURL)
答案 0 :(得分:3)
我猜是这样的:
public static List<XDocument> GetResources(string startURL)
{
var result = new List<XDocument>();
var doc = XDocument.Parse(GetXml(startURL));
var xs = new XmlSerializer(typeof(resourceList));
var rdr = doc.CreateReader();
if (xs.CanDeserialize(rdr))
{
var rl = (resourceList)xs.Deserialize(doc.CreateReader());
foreach (var item in rl.resourceURL)
{
result.AddRange(GetResources(startURL + item.location));
}
}
else
{
result.Add(doc);
}
return result;
}
答案 1 :(得分:2)
首先,首先是ref
参数绝对没有意义。您很可能无法理解ref
参数 - 请参阅my article on this topic。
由于这是自然递归,我可能会这样写:
public static List<XDocument> GetResources(string startURL)
{
List<XDocument> ret = new List<XDocument>();
GetResourcesRecursive(startURL, ret);
return ret;
}
private static void GetResourcesRecursive(string startURL,
List<XDocument> result)
{
var doc = XDocument.Parse(GetXml(startURL));
var xs = new XmlSerializer(typeof(resourceList));
var rdr = doc.CreateReader();
if (xs.CanDeserialize(rdr))
{
var rl = (resourceList)xs.Deserialize(doc.CreateReader());
foreach (var item in rl.resourceURL)
{
GetResourcesRecursive(startURL + item.location, ref result);
}
}
else
{
result.Add(doc);
}
}
你可以以递归方式保存它并在每个级别创建一个新列表,但对我来说感觉有点难看。上面为您提供了所需的 public API,但没有分配左,右和中心的集合。
现在你可以以非递归的方式编写它,基本上是通过创建一个URL队列来完成:
public static List<XDocument> GetResources(string startURL)
{
List<XDocument> ret = new List<XDocument>();
Queue<string> urls = new Queue<string>();
urls.Enqueue(startUrl);
while (urls.Count > 0)
{
string url = urls.Dequeue();
var doc = XDocument.Parse(GetXml(url));
var xs = new XmlSerializer(typeof(resourceList));
var rdr = doc.CreateReader();
if (xs.CanDeserialize(rdr))
{
var rl = (resourceList) xs.Deserialize(doc.CreateReader());
foreach (var item in rl.resourceURL)
{
queue.Enqueue(url + item.location);
}
}
else
{
ret.Add(doc);
}
}
return ret;
}
现在为时已晚,让我弄清楚这是否会以相同的顺序给出结果 - 我怀疑它没有 - 但希望这并不重要。
(你不真的有一个名为resourceList
的类型吗?ResourceList
,请!)
答案 2 :(得分:2)
代码看起来很好(减去参数上不必要的ref
。)一种选择是将递归方法包装在非递归伴侣中:
public static List<XDocument> GetResources(string startURL)
{
List<XDocument> retDocs = new List<XDocument>();
GetResources(startURL, retDocs);
return retDocs;
}
答案 3 :(得分:1)
嗯,我有一个偶尔使用的模式,我想把它作为一个选项展示。然而,当我试图按照书面处理它时,我的大脑有点剔除,所以我们达成了一个协议(我的大脑和我),我们只想找出一个简单的版本来向你展示。
它可能甚至不适用于您的具体问题,但这是我过去使用的一种方式,当我希望以不可变的方式完成任务时,这似乎是您正在寻找的。 p >
public string IntCSVReverse(List<int> IntList)
{
return IntCSVReverse_recurse(IntList, 0);
}
private string IntCSVReverse_recurse(List<int> IntList, int Index)
{
if (Index == (IntList.Count - 1))
return IntList[Index].ToString();
else
return
IntCSVReverse_recurse(IntList, Index + 1)
+ "," + IntList[Index].ToString();
}
所以,有这样的模式,它的价值。它不是XML,它不是分支,但它是一个简洁的例子,当非变异递归很容易实现并且比我试图通过改变{{1 }}。
实际上,您的特定示例似乎更好(对我而言)作为两步解决方案,在开头创建了一个List返回值。 :)