小编Jep*_*sen的帖子

为什么微软希望不用NaN修复错误的Equals和GetHashCode实现?

在.NET Framework中,实现(override中)Equals(object)GetHashCode()浮点型(System.DoubleSystem.Single)是错误的.引用MSDN GetHashCode(object)规范:

哈希函数必须具有以下属性:

•如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值.但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值.

如果NaN使用具有不同二进制表示的两个值,则这两个对象在该Equals方法下比较相等,但哈希码(几乎总是)是不同的.

现在,Microsoft Connect 已报告此错误.但他们为什么不解决这个问题?

修复很简单:让不同的NaN 比较相同,或选择一个固定的哈希代码返回任何NaN.

修复不会破坏任何东西:今天的方式,当使用不同的东西时没有任何作用NaN.

你能想出任何不解决这个问题的理由吗?

这是一个说明当前行为的简单示例:

using System;
using System.Collections.Generic;
using System.Linq;

static class Program
{
  const int setSize = 1000000; // change to higher value if you want to waste even more memory
  const double oneNaNToRuleThemAll = double.NaN;
  static readonly Random randomNumberGenerator …
Run Code Online (Sandbox Code Playgroud)

.net c# floating-point hash nan

16
推荐指数
0
解决办法
384
查看次数

在方法覆盖中更改params修饰符

我知道params修饰符(将数组类型的一个参数转换为所谓的"参数数组")特别不是方法签名的一部分.现在考虑这个例子:

class Giraffid
{
    public virtual void Eat(int[] leaves)
    {
        Console.WriteLine("G");
    }
}
class Okapi : Giraffid
{
    public override void Eat(params int[] leaves)
    {
        Console.WriteLine("O");
    }
}
Run Code Online (Sandbox Code Playgroud)

编译时没有任何警告.然后说:

var okapi = new Okapi();
okapi.Eat(2, 4, 6);  // will not compile! 
Run Code Online (Sandbox Code Playgroud)

给出一个错误(No overload for method 'Eat' takes 3 arguments).

现在,我知道编译器会将params修改器转换为System.ParamArrayAttribute相关参数的应用程序.通常,将一个属性集合应用于虚方法的参数,然后在具有不同属性集的派生类中的重写方法中装饰"对应"参数是没有问题的.

然而,编译器选择params静默忽略我的关键字.相反,如果一个使它反过来,并且应用于params基类中的参数Giraffid,然后省略覆盖中的关键字Okapi,编译器选择用它来装饰两个方法System.ParamArrayAttribute.当然,我用IL DASM验证了这些东西.

我的问题:

这是记录在案的行为?我已经彻底搜索了C#语言规范,但没有发现任何提及.

我可以说至少Visual Studio开发环境对此感到困惑.当键入2, 4, 6在上述方法的调用,所述 …

c# overriding virtual-functions params-keyword params

16
推荐指数
2
解决办法
1121
查看次数

为什么编译器在这种重载决策情况下不能告诉更好的转换目标?(协方差)

理解关于重载解析的C#语言规范显然很难,现在我想知道为什么这个简单的情况失败了:

void Method(Func<string> f)
{
}
void Method(Func<object> f)
{
}
void Call()
{
    Method(() => { throw new NotSupportedException(); });
}
Run Code Online (Sandbox Code Playgroud)

这给出了编译时错误CS0121,以下方法或属性之间的调用是不明确的:后跟我的两个Method函数成员(重载).

我本来期望的是,Func<string>是一个更好的转换目标Func<object>,然后应使用第一个重载.

由于.NET 4和C#4(2010),通用委托类型Func<out TResult>协变TResult,并且由于该原因的隐式转换从存在Func<string>Func<object>同时明确的隐式转换可以从存在Func<object>Func<string>.那么它会产生Func<string>更好的转换目标,而重载分辨率应该选择第一个过载?

我的问题很简单:我在这里错过了C#规范的哪一部分?


增加:这很好用:

void Call()
{
    Method(null); // OK!
}
Run Code Online (Sandbox Code Playgroud)

c# delegates overloading covariance overload-resolution

16
推荐指数
1
解决办法
636
查看次数

.NET的Double.ToString方法中的Round-two错误

在数学上,考虑这个问题的有理数

8725724278030350 / 2**48
Run Code Online (Sandbox Code Playgroud)

其中**在分母表示取幂,即,分母是248次方.(分数不在最低方面,通过2可还原的)此数目是恰好作为表示的System.Double.它的十进制扩展是

31.0000000000000'49'73799150320701301097869873046875 (exact)
Run Code Online (Sandbox Code Playgroud)

撇号不代表缺失的数字,而只是标记圆形到15的分数.将执行17位数字.

请注意以下内容:如果此数字四舍五入为15位,则结果为31(后跟十三0秒),因为下一个数字(49...)以a开头4(意味着向下舍入).但如果数字首先四舍五入为17位,然后四舍五入为15位,结果可能是31.0000000000001.这是因为第一次舍入通过将49...数字增加到50 (terminates)(下一个数字73...)而向上舍入,然后第二次舍入可能再次向上舍入(当中点舍入规则表示"从零开始舍入"时).

(当然,还有更多具有上述特征的数字.)

现在,事实证明.NET的这个数字的标准字符串表示是"31.0000000000001".问题:这不是一个错误吗?通过标准字符串表示,我们指的String是由参数Double.ToString()实例方法产生的,当然,该方法与生成的方法相同ToString("G").

需要注意的一个有趣的事情是,如果你投的上述号码System.Decimal,然后你得到一个decimal31准确!请参阅此Stack Overflow问题,以讨论将a转换DoubleDecimal包含第一个舍入到15位的令人惊讶的事实.这意味着转换为Decimal正确的舍入到15位数,而调用ToSting()是不正确的.

总而言之,我们有一个浮点数,当输出给用户时,是31.0000000000001,但当转换为Decimal …

.net c# floating-point rounding

15
推荐指数
2
解决办法
1965
查看次数

为什么System.DateTime结构具有布局类型Auto?

结构System.DateTime及其表兄System.DateTimeOffset的结构布局类型设置为"自动".这可以看作:

typeof(DateTime).IsAutoLayout    /* true */
Run Code Online (Sandbox Code Playgroud)

要么:

typeof(DateTime).StructLayoutAttribute.Value    /* Auto */
Run Code Online (Sandbox Code Playgroud)

或者从IL中可以看出它声明:

.class public auto ansi serializable sealed beforefieldinit System.DateTime
              ¯¯¯¯
Run Code Online (Sandbox Code Playgroud)

通常,使用C#编写的结构(即不是枚举的.NET值类型)将具有"顺序"布局(除非StructLayoutAttribute已应用指定另一个布局).

我通过一些常见的搜索BCL组件,以及DateTimeDateTimeOffset是唯一公开可见的结构,我发现用这个布局.

有谁知道为什么DateTime这个不寻常的结构布局?

.net c# datetime struct structlayout

14
推荐指数
1
解决办法
904
查看次数

当替换类型参数后两个方法具有相同的签名时,将覆盖错误的重载

我们相信这个例子在C#编译器中出现了一个错误(如果我们错了,请取笑我).这个错误可能是众所周知的:毕竟,我们的示例是对此博客文章中描述的内容的简单修改.

using System;

namespace GenericConflict
{
  class Base<T, S>
  {
    public virtual int Foo(T t)
    { return 1; }
    public virtual int Foo(S s)
    { return 2; }

    public int CallFooOfT(T t)
    { return Foo(t); }
    public int CallFooOfS(S s)
    { return Foo(s); }
  }

  class Intermediate<T, S> : Base<T, S>
  {
    public override int Foo(T t)
    { return 11; }
  }

  class Conflict : Intermediate<string, string>
  {
    public override int Foo(string t)
    { return 101;  }
  } …
Run Code Online (Sandbox Code Playgroud)

c# compiler-construction generics overriding overload-resolution

12
推荐指数
1
解决办法
695
查看次数

System.Reflection.RuntimeReflectionExtensions中方法的目的是什么?

从.NET 4.5(2012)开始,一些新的扩展方法出现在System.Reflection.RuntimeReflectionExtensions类中.然而,新方法似乎没有给我们任何新的东西.一个例子:

static void Main()
{
    var prop1 = typeof(string).GetProperty("Length");
    var prop2 = typeof(string).GetRuntimeProperty("Length");  // extension, needs: using System.Reflection;
    Console.WriteLine(prop1 == prop2);

    Action a = Main;
    var meth1 = a.Method;
    var meth2 = a.GetMethodInfo();  // extension, needs: using System.Reflection;
    Console.WriteLine(meth1 == meth2);
}
Run Code Online (Sandbox Code Playgroud)

这写了True两次.

(==操作符在这里超载,但甚至检查参考相等性(object)prop1 == (object)prop2(object)meth1 == (object)meth2给出True).

那么这些新的公开可见方法的目的是什么?显然,我必须忽略或误解某些东西.

.net c# reflection base-class-library .net-4.5

12
推荐指数
1
解决办法
1259
查看次数

为什么一系列nullables的Linq-to-Objects总和本身可以为空?

像往常一样,int?意味着System.Nullable<int>(或System.Nullable`1[System.Int32]).

假设你有一个内存IEnumerable<int?>(例如一个List<int?>),让我们称之为seq; 然后你可以找到它的总和:

var seqSum = seq.Sum();
Run Code Online (Sandbox Code Playgroud)

当然这是扩展方法重载int? IEnumerable<int?>.Sum()(文档),它实际上是一个静态方法System.Linq.Enumerable.

但是,该方法永远不会返回null,为什么返回类型声明为Nullable<>即使在seq空集合或更一般地集合的所有元素都是null类型的值的情况下int?,所讨论的Sum方法仍然返回零,而不是null.

这从文档中可以看出,也可以从System.Core.dll源代码中看出:

public static int? Sum(this IEnumerable<int?> source) { 
    if (source == null) throw Error.ArgumentNull("source"); 
    int sum = 0; 
    checked { 
        foreach (int? v in source) { 
            if (v != null) sum += v.GetValueOrDefault(); 
        } 
    } 
    return sum; …
Run Code Online (Sandbox Code Playgroud)

c# linq nullable sum base-class-library

12
推荐指数
1
解决办法
301
查看次数

属性规范中的奇怪歧义(两个使用指令)

背景:属性规范中,有时存在两种写入应用属性的有效方法。例如,如果属性类具有名称HorseAttribute,则可以将属性应用为[HorseAttribute][Horse]。歧义可以用@例如来解决[@Horse]

以下是有效的程序:

using System;
using Alpha;
using Beta;

namespace N
{
  [Horse]
  class C
  {
  }
}

namespace Alpha
{
  // valid non-abstract attribute type with accessible constructor
  class HorseAttribute : Attribute
  {
  }
}

namespace Beta
{
  // any non-attribute type with that name
  enum Horse
  {
  }
}
Run Code Online (Sandbox Code Playgroud)

Alpha.HorseAttribute我编写just时,C#编译器可以选择[Horse]。毕竟,类型Beta.Horse完全不适合在属性规范中使用。

即使交换名称,C#编译器也会知道该怎么做:

using System;
using Alpha;
using Beta;

namespace N
{
  [Horse] …
Run Code Online (Sandbox Code Playgroud)

c# compiler-errors custom-attributes .net-attributes

12
推荐指数
1
解决办法
284
查看次数

将struct与null进行比较时,编译器警告错误

请考虑以下代码:

DateTime t = DateTime.Today;

bool isGreater = t > null;
Run Code Online (Sandbox Code Playgroud)

使用Visual Studio 2010(C#4,.NET 4.0),我收到以下警告:

警告CS0458:表达式的结果始终为'bool'类型的'null'

这是不正确的; 结果总是false(类型bool):

现在,struct DateTime重载>(大于)运算符.任何不可为空的结构(如DateTime)都可以隐式转换为相应的Nullable<>类型.上面的表达式完全相同

bool isGreater = (DateTime?)t > (DateTime?)null;
Run Code Online (Sandbox Code Playgroud)

这也产生了同样的错误警告.在这里,>操作员是提升的操作员.如果HasValue其两个操作数中的任何一个是,则返回false false.否则,提升的运算符将继续将两个操作数展开到底层结构,然后调用该>结构定义的重载(但在这种情况下,这不是必需的,其中一个操作数不是HasValue).

你能重现这个bug,这个bug是众所周知的吗?我误解了什么吗?

对于所讨论int的运算符重载的所有结构类型(不是简单类型,而不是枚举类型),这是相同的.

(现在如果我们使用==而不是>,那么一切都应该完全相似(因为DateTime也会使==运算符超载).但它不相似.如果我说

DateTime t = DateTime.Today;

bool isEqual = t == null;
Run Code Online (Sandbox Code Playgroud)

没有得到警告☹有时候你会看到人们不小心检查变量或参数为null,没有意识到他们的变量类型是一个结构(它过载==而且不是一个简单的类型int).如果他们得到警告会更好.)


更新:使用Visual Studio 2015的C#6.0编译器(基于 Roslyn …

c# comparison nullable compiler-warnings lifted-operators

11
推荐指数
2
解决办法
941
查看次数