昨天需要操作用代碼操作csproj文件,實現不同vs版本的切換。
在用XElement讀取了csproj文件以後怎麼也獲取不到想要的對象。
反反復復試驗了好多次都不得要領:先看下csproj文件的內容:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EC9D3364-405E-4931-8148-779183C72A40}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>AsyncDemo</RootNamespace>
<AssemblyName>AsyncDemo</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
</Project>
因為只是為了說明問題,我只截取了一部分csproj文件
我最初的代碼是:
XDocument doc = XDocument.Load(@"D:\Demo\AsyncDemo\AsyncDemo\AsyncDemo.csproj");
XElement x = doc.Element("Project");
這個x始終為空,最後分析了下doc對象

果然找到了玄機,這個name並不是一個單純“project”,還帶有命名空間。
那麼如何獲得這個帶有Namespace的節點名哪?
好吧,讓我們回過頭來看看XElement的構造函數:
public XElement(XName name);
注意哦,參數的類型是XName,而不是string,那麼平時為什麼能用string哪?XName定義了一個隱式的轉換,可以把string隱式的轉換成XName。
所以,關於Namespace自然也要從XNamespace入手,然後找一個能夠變成XName的方法,察看XNamespace的定義,就可以看到:
public static XName operator +(XNamespace ns, string localName);
只要把XNamespace加上本地名稱(string),就是一個XName了,非常簡單。
再看看如何創建一個XNamespace:
public static implicit operator XNamespace(string namespaceName);
又是隱式轉換。。。來看看具體如何創建一個帶namespace的project吧:
static void TestXml()
{
XDocument doc = XDocument.Load(@"D:\Demo\AsyncDemo\AsyncDemo\AsyncDemo.csproj");
XNamespace v = "http://schemas.microsoft.com/developer/msbuild/2003";
XElement x = doc.Element(v + "Project");
}
定義一個namespace,在使用時直接+string即可。這樣就可以得到我們想要的對象了,具體操作代碼如下:
static void TestXml()
{
string path = @"D:\Demo\AsyncDemo\AsyncDemo\AsyncDemo.csproj";
XDocument doc = XDocument.Load(path);
XNamespace v = "http://schemas.microsoft.com/developer/msbuild/2003";
var x = doc.Element(v + "Project").Elements(v+"PropertyGroup");
foreach (var e in x)
{
XElement element = e.Element(v + "AssemblyName");
if(element!=null)
{
element.SetValue("abcd");
}
}
doc.Save(path);
}
這裡面所有需要操作的節點都要采用命名空間加節點名的方式。
希望對您有所幫助……