我想修改对象中包含的一些字符串,比如数组,或者XDocument(XText)XNode.Value.中的节点
我想从这些对象中收集字符串的子集并修改它们,但在运行时我不知道它们来自什么对象类型。
换句话说,假设我有这样的对象:
List<string> fruits = new List<string>() {"apple", "banana", "cantelope"};
XDocument _xmlObject;
我希望能够将原始集合中的值的子集添加到新列表中,如下所示:
List<ref string> myStrings1 = new List<ref string>();
myStrings1.Add(ref fruits[1]);
myStrings1.Add(ref fruits[2]);
List<ref string> myStrings2 = new List<ref string>();
IEnumerable<XNode> xTextNodes = getTargetTextNodes(targetPath); //some function returns a series of XNodes in the XDocument
foreach (XNode node in xTextNodes)
{
myStrings2.Add(((XText)node).Value);
}
然后使用以下通用方法更改值:
public void Modify(List<ref string> mystrings){
foreach (ref string item in mystrings)
{
item = "new string";
}
}
这样我就可以将该方法传递给任何字符串集合,并修改原始对象中的字符串,而不必处理原始对象本身。
static void Main(string[] args)
{
Modify(myStrings1);
Modify(myStrings2);
}
这里的重要部分是mystrings
集合。这可能很特别。但我需要能够使用各种不同类型的字符串和字符串集合作为原始源数据,以进入该集合。
当然,上面的代码不起作用,我尝试过的任何变体也不起作用。这在c#中可能吗?
您想要的东西在C#中是可能的,但前提是可以修复字符串的所有可能源这将允许您使用指向原始字符串的指针。。。然而,在整个应用程序的内存管理和不安全代码方面,付出了巨大的代价。
我鼓励你为此寻求不同的方向。
根据您的编辑,看起来您总是在处理整个集合,并且总是一次修改整个集合。此外,这在一开始甚至可能不是一个字符串集合。我认为您无法获得所需的确切结果,因为您正在使用的基本XDocument类型。但一个可能的探索方向可能是这样的:
public IEnumerable<string> Modify(IEnumerable<string> items)
{
foreach(string item in items)
{
yield return "blah";
}
}
您可以使用投影从任何集合类型获取字符串,并返回修改后的文本:
fruits = Modify(fruits).ToList();
var nodes = Modify( xTextNodes.Select(n => (XText)n.Value));
一旦你了解了如何进行投影,你可能会发现现有的.Select()
方法已经完成了你需要的一切。
不过,我真正的建议是,与其处理整个收藏,不如考虑一次处理一张唱片。创建一个所有数据源都能理解的通用对象类型。创建从每个数据源到公共对象类型的投影。循环浏览投影中的每个对象并进行调整。然后将另一个投影返回到原始记录类型这将不是原始集合。这将是一个新的系列。将新收藏写回磁盘。
如果使用得当,这也有可能使比原来的方法具有更高的性能。这是因为使用这些linq投影,一次处理一个记录,打开了数据流的大门,这样一次只有一个当前记录保存在内存中。您可以打开原始文件中的流和输出的流,并以与读取原始文件一样快的速度写入输出。
实现这一点的最简单方法是在方法之外进行循环。这允许您通过引用传递字符串,这将用新的引用替换现有的引用(不要忘记字符串是不可变的)。
举个例子:
void Main()
{
string[] arr = new[] {"lala", "lolo"};
arr.Dump();
for(var i = 0; i < arr.Length; i++)
{
ModifyStrings(ref arr[i]);
}
arr.Dump();
}
public void ModifyStrings(ref string item)
{
item = "blah";
}