为什么 DbParameterCollection 中的三个属性在引用程序集中是抽象的,而在其他情况下是虚拟的?
Why are three properties in DbParameterCollection abstract in reference assemblies but virtual otherwise?
我正在将一个项目从 project.json
移动到新式 csproj 格式,它包括一个从 DbParameterCollection
派生的 class。在我的真实项目中,我使用的是多目标,但出于这个问题的目的,我们只需要关心 net45
.
编译器告诉我必须覆盖三个以前不需要的属性:
如果您点击那些文档链接(适用于 .NET 4.5),您将看到所有属性都是 虚拟的 - 不是抽象的。如果我只是通过调用 csc
来构建代码,一切都很好......只有在使用 .NET Core SDK 时我 运行 才会遇到这个问题。
下面是重现问题的示例代码:
项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net45</TargetFramework>
</PropertyGroup>
</Project>
C#代码:
using System;
using System.Collections;
using System.Data.Common;
public class DummyParameterCollection : DbParameterCollection
{
public override int Count => 0;
public override object SyncRoot => null;
public override void Remove(object value) {}
public override void RemoveAt(int index) {}
public override void RemoveAt(string parameterName) {}
public override int Add(object value) => 0;
public override void Insert(int index, object value) {}
public override void AddRange(Array values) {}
public override void Clear() {}
public override bool Contains(object value) => false;
public override bool Contains(string value) => false;
public override void CopyTo(Array array, int index) {}
public override int IndexOf(object value) => -1;
public override int IndexOf(string parameterName) => -1;
protected override DbParameter GetParameter(int index) => null;
protected override DbParameter GetParameter(string parameterName) => null;
protected override void SetParameter(int index, DbParameter value) {}
protected override void SetParameter(string parameterName, DbParameter value) {}
public override IEnumerator GetEnumerator() => null;
}
错误:
DummyParameterCollection.cs(5,14): error CS0534: 'DummyParameterCollection' does not implement inherited abstract member 'DbParameterCollection.IsSynchronized.get' [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
DummyParameterCollection.cs(5,14): error CS0534: 'DummyParameterCollection' does not implement inherited abstract member 'DbParameterCollection.IsFixedSize.get' [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
DummyParameterCollection.cs(5,14): error CS0534: 'DummyParameterCollection' does not implement inherited abstract member 'DbParameterCollection.IsReadOnly.get' [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
我相信我知道问题的直接原因,但不知道为什么会这样,或者最好的解决方法。
看起来 .NET Core SDK(以及加载此项目时的 VS2017)使用了参考程序集。如果我在 Reflector 中打开 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll
,that 也会将属性显示为抽象的。而如果我打开 c:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
,则会显示属性是虚拟的。
我可以通过覆盖属性并从所有属性中返回 false
来解决这个问题 - 但这是处理这种情况的最佳方式吗?除此之外,在这种情况下,参考程序集与真实程序集(和文档)不匹配有什么充分的理由吗?我希望参考程序集是自动生成的,所以 某些 事情像这样不正确是很奇怪的...
参考程序集是正确的。在 .NET Framework 4.5 中,这些属性为 abstract
。它们在 .NET Framework 4.5.1 中更改为 virtual
。您似乎发现了文档错误。
正如您可能已经猜到的那样,您所观察到的两个 System.Data.dll 程序集之间的差异是由于 .NET Framework 分隔引用程序集和运行时程序集的方式所致。 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll
中的参考程序集准确反映了 System.Data.dll
的 4.5 运行时版本中的内容。如果您能够获得一台尚未升级到 .NET Framework 4.5.1 的旧计算机(祝您好运),您会发现 C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
中的运行时程序集具有 abstract
中的这些属性. .NET Framework 就地升级。在已升级到 .NET Framework 4.5.1 或更新版本的计算机上,C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
已替换为更新版本(具有 virtual
,而不是 abstract
属性。)
至于解决方法:为 net451
编译,或者实施虚拟方法是最好的方法。您可以使用其他技巧针对不同版本的 System.Data.dll 进行编译,但我不推荐它
我找不到关于 .NET Framework 4.5 和 4.5.1 之间 API 更改的官方文档,也找不到更改原因的解释,但是,我从 Entity Framework队:https://bugzilla.xamarin.com/show_bug.cgi?id=29167#c0。
The following (non-breaking) changes were made to the System.Data APIs in the .NET Framework 4.5.1 release....
The following member were added.
- System.Data.Common.DbParameter.Precision
- System.Data.Common.DbParameter.Scale
- System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryCount
- System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryInterval
The following member were changed from abstract to virtual.
- System.Data.Common.DbDataReader.Close
- System.Data.Common.DbDataReader.GetSchemaTable
- System.Data.Common.DbParameter.SourceVersion
- System.Data.Common.DbParameterCollection.IsFixedSize
- System.Data.Common.DbParameterCollection.IsReadOnly
- System.Data.Common.DbParameterCollection.IsSynchronized
我正在将一个项目从 project.json
移动到新式 csproj 格式,它包括一个从 DbParameterCollection
派生的 class。在我的真实项目中,我使用的是多目标,但出于这个问题的目的,我们只需要关心 net45
.
编译器告诉我必须覆盖三个以前不需要的属性:
如果您点击那些文档链接(适用于 .NET 4.5),您将看到所有属性都是 虚拟的 - 不是抽象的。如果我只是通过调用 csc
来构建代码,一切都很好......只有在使用 .NET Core SDK 时我 运行 才会遇到这个问题。
下面是重现问题的示例代码:
项目文件:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net45</TargetFramework>
</PropertyGroup>
</Project>
C#代码:
using System;
using System.Collections;
using System.Data.Common;
public class DummyParameterCollection : DbParameterCollection
{
public override int Count => 0;
public override object SyncRoot => null;
public override void Remove(object value) {}
public override void RemoveAt(int index) {}
public override void RemoveAt(string parameterName) {}
public override int Add(object value) => 0;
public override void Insert(int index, object value) {}
public override void AddRange(Array values) {}
public override void Clear() {}
public override bool Contains(object value) => false;
public override bool Contains(string value) => false;
public override void CopyTo(Array array, int index) {}
public override int IndexOf(object value) => -1;
public override int IndexOf(string parameterName) => -1;
protected override DbParameter GetParameter(int index) => null;
protected override DbParameter GetParameter(string parameterName) => null;
protected override void SetParameter(int index, DbParameter value) {}
protected override void SetParameter(string parameterName, DbParameter value) {}
public override IEnumerator GetEnumerator() => null;
}
错误:
DummyParameterCollection.cs(5,14): error CS0534: 'DummyParameterCollection' does not implement inherited abstract member 'DbParameterCollection.IsSynchronized.get' [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
DummyParameterCollection.cs(5,14): error CS0534: 'DummyParameterCollection' does not implement inherited abstract member 'DbParameterCollection.IsFixedSize.get' [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
DummyParameterCollection.cs(5,14): error CS0534: 'DummyParameterCollection' does not implement inherited abstract member 'DbParameterCollection.IsReadOnly.get' [c:\Users\skeet\Test\ParameterCollection\ParameterCollection.csproj]
我相信我知道问题的直接原因,但不知道为什么会这样,或者最好的解决方法。
看起来 .NET Core SDK(以及加载此项目时的 VS2017)使用了参考程序集。如果我在 Reflector 中打开 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll
,that 也会将属性显示为抽象的。而如果我打开 c:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
,则会显示属性是虚拟的。
我可以通过覆盖属性并从所有属性中返回 false
来解决这个问题 - 但这是处理这种情况的最佳方式吗?除此之外,在这种情况下,参考程序集与真实程序集(和文档)不匹配有什么充分的理由吗?我希望参考程序集是自动生成的,所以 某些 事情像这样不正确是很奇怪的...
参考程序集是正确的。在 .NET Framework 4.5 中,这些属性为 abstract
。它们在 .NET Framework 4.5.1 中更改为 virtual
。您似乎发现了文档错误。
正如您可能已经猜到的那样,您所观察到的两个 System.Data.dll 程序集之间的差异是由于 .NET Framework 分隔引用程序集和运行时程序集的方式所致。 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Data.dll
中的参考程序集准确反映了 System.Data.dll
的 4.5 运行时版本中的内容。如果您能够获得一台尚未升级到 .NET Framework 4.5.1 的旧计算机(祝您好运),您会发现 C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
中的运行时程序集具有 abstract
中的这些属性. .NET Framework 就地升级。在已升级到 .NET Framework 4.5.1 或更新版本的计算机上,C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll
已替换为更新版本(具有 virtual
,而不是 abstract
属性。)
至于解决方法:为 net451
编译,或者实施虚拟方法是最好的方法。您可以使用其他技巧针对不同版本的 System.Data.dll 进行编译,但我不推荐它
我找不到关于 .NET Framework 4.5 和 4.5.1 之间 API 更改的官方文档,也找不到更改原因的解释,但是,我从 Entity Framework队:https://bugzilla.xamarin.com/show_bug.cgi?id=29167#c0。
The following (non-breaking) changes were made to the System.Data APIs in the .NET Framework 4.5.1 release....
The following member were added.
- System.Data.Common.DbParameter.Precision
- System.Data.Common.DbParameter.Scale
- System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryCount
- System.Data.SqlClient.SqlConnectionStringBuilder.ConnectRetryInterval
The following member were changed from abstract to virtual.
- System.Data.Common.DbDataReader.Close
- System.Data.Common.DbDataReader.GetSchemaTable
- System.Data.Common.DbParameter.SourceVersion
- System.Data.Common.DbParameterCollection.IsFixedSize
- System.Data.Common.DbParameterCollection.IsReadOnly
- System.Data.Common.DbParameterCollection.IsSynchronized