Если HashCode принадлежит файлу, почему он не является его подэлементом / атрибутом?Это упростило бы анализ.
Поскольку вы создаете файл, я бы создал структуру, например:
<Project Name="tfasdtyf">
<TestCycle Number="23423">
<Files>
<File Name="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\DllTest.dll" HashCode="0E-C5-03-AD-CC-21-62-49-D9-36-3F-C4-F1-17-BC-11" />
<File Name="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.exe" HashCode="60-46-A3-6F-82-E4-0A-00-2A-60-83-47-B2-16-F3-24" />
<File Name="C:\Users\brandonm\Documents\Visual Studio 2008\Projects\WpfDllTest\WpfDllTest\bin\x86\Release\WpfDllTest.vshost.exe" HashCode="76-7B-6F-37-0D-3A-F2-F4-32-D1-70-A5-75-3B-DE-95" />
</Files>
</TestCycle>
</Project>
Затем, используя магию XElement, вы можете использовать:
public class Project
{
XElement self;
public Project(XElement project)
{
self = project;
}
public TestCycle TestCycle
{
get
{
// If there are more than one TestCycle per project, you may end
// up creating something similar to TestCycle.Files (see TestCycle class below)
XElement testCycle = self.Element("TestCycle");
if(null == testCycle)
self.Add(testCycle = new XElement("TestCycle"));
return new TestCycle(testCycle);
}
}
public string Name
{
get { return return self.GetString("Name", string.Empty, ATTRIBUTE); }
set { self.Set("Name", value, ATTRIBUTE); } // see Set Extension method below
}
public static IEnumerable<Project> Load(string filename)
{
return XElement.Load(filename)).Elements("Project").Select(xp => new Project(xp));
}
}
public class TestCycle
{
XElement self;
public TestCycle(XElement testCycle)
{
self = testCycle;
}
private XElement XFiles
{
get
{
XElement files = self.Element("Files");
if(null == files)
self.Add(files = new XElement("Files"));
return files;
}
}
public IEnumerable<FileHash> Files
{
get
{
return XFiles.Elements("File").Select(xf => new FileHash(xf));
}
}
public int Number
{
get { return self.GetInt("Number", 0, ATTRIBUTE); }
set { self.Set("Number", value, ATTRIBUTE); } // see Set Extension method below
}
public FileHash AddFile(string name, string hashCode)
{
FileHash file = Files.FirstOrDefault(xf => xf.Name == name);
if(null != file)
file.self.Remove(); // replacing (but could throw an exception saying already exists instead)
XElement xFile = new XElement("File");
self.Add(xFile);
file = new FileHash(xFile)
{
Name = name,
HashCode = hashCode
};
return file;
}
}
public class FileHash
{
internal XElement self;
public FileHash(XElement fileHash)
{
self = fileHash;
}
public string Name
{
get { return self.GetString("Name", string.Empty, ATTRIBUTE); }
set { self.Set("Name", value, ATTRIBUTE); } // see Set Extension method below
}
public string HashCode
{
get { return return self.GetString("HashCode", string.Empty, ATTRIBUTE); }
set { self.Set("HashCode", value, ATTRIBUTE); } // see Set Extension method below
}
}
Методы расширения:
public static XElementExtensions
{
public const bool ATTRIBUTE = true;
public const bool ELEMENT = false;
public const bool? BOTH = null;
public void Set(this XElement self, string name, object value, bool isAttribute)
{
string sValue = value.ToString();
XElement eValue = self.Element(name);
XAttribute aValue = self.Attribute(name);
if(null != eValue)
eValue.ReplaceWith(new XElement(name, sValue));
else if(null != aValue)
aValue.ReplaceWith(new XAttribute(name, sValue));
else if(isAttribute)
self.Add(new XAttribute(name, sValue));
else
self.Add(new XElement(name, sValue));
}
public string GetString(this XElement self, string name, string @default, bool? isAttribute)
{
XAttribute aValue = self.Attribute(name);
XElement eValue = self.Element(name);
if(null == isAttribute) // try both
{
if(null != aValue) return (string)aValue;
if(null != eValue) return (string)eValue;
return @default;
}
if(isAttribute && null != aValue)
return (string)aValue;
if(!isAttribute && null != eValue)
return (string)eValue);
return @default;
}
public int GetInt(this XElement self, string name, int @default, bool? isAttribute)
{
return Convert
.ToInt32(GetString(self, name, null, isAttribute) ?? @default.ToString());
}
}
Затем вы можете использовать код, например:
Project[] projects = Project.Load(filename).ToArray();
foreach(Project project in projects)
{
Console.WriteLine("Project: " + project.Name);
Console.WriteLine("TestCycle: " + project.TestCycle.Number.ToString());
Console.WriteLine("Files:");
foreach(FileHash file in project.TestCycle.Files)
Console.WriteLine(string.Format(" Name: {0}, HashCode: {1}", file.Name, file.HashCode));
}
Или для вашего приложения, чтобы сравнить два файла XML:
var fileA = Project.Load(fileAname);
var fileB = Project.Load(fileBname);
Я не совсем уверен, что вы имеете в виду, все файлы, но я попробую.
File[] filesA = fileA.SelectMany(project => project.TestCycle.Files).ToArray();
File[] filesB = fileB.SelectMany(project => project.TestCycle.Files).ToArray();
Использование этих методов расширения:
public static IEnumerable<TSource> Except<TSource>
(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TSource, bool> comparer
)
{
return first.Except(second, new LambdaComparer<TSource>(comparer));
}
public static IEnumerable<TSource> Intersect<TSource>
(
this IEnumerable<TSource> first,
IEnumerable<TSource> second,
Func<TSource, TSource, bool> comparer
)
{
return first.Intersect(second, new LambdaComparer<TSource>(comparer));
}
И класс LambdaComparer:
public class LambdaComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> equals;
private readonly Func<T, int> getHashCode;
public LambdaComparer(Func<T, T, bool> lambdaComparer) :
this(lambdaComparer, o => o.GetHashCode())
{
}
public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
{
if (lambdaComparer == null)
throw new ArgumentNullException("lambdaComparer");
if (lambdaHash == null)
throw new ArgumentNullException("lambdaHash");
equals = lambdaComparer;
getHashCode = lambdaHash;
}
public bool Equals(T x, T y)
{
return equals(x, y);
}
public int GetHashCode(T obj)
{
return getHashCode(obj);
}
}
File[] filesInA_butNotInB = filesA.Except(filesB, (a,b) => a.Name == b.Name).ToArray();
File[] filesInBoth = filesA.Intersect(filesB, (a,b) => a.Name == b.Name).ToArray();
File[] filesInBoth_butDifferentHash = FilesA.Intersect(filesB, (a,b) => a.Name == b.Name && a.HashCode != b.HashCode).ToArray();
Это должно "начать" ...
PS: я написал (почти все) это все вручную, а нечерез компилятор, так что, вероятно, есть некоторые опечатки, которые компилятор поймает.
PS: Кроме того, все .ToArray()'s
только потому, что File[]
легче читать, чем IEnumerable<File>
.Это легче читать, но о той же печати в любом случае.
PSS: Я надеюсь, что вы найдете это полезным.Мне нравится способ работы с Xml Linq, так что это было забавно писать это.