我不确定这种说明Stack Overflow问题的非标准方式是好还是坏,但是这里是:
什么是最好的(数学或其他技术)解释为什么代码:
static void Main()
{
decimal[] arr =
{
42m,
42.0m,
42.00m,
42.000m,
42.0000m,
42.00000m,
42.000000m,
42.0000000m,
42.00000000m,
42.000000000m,
42.0000000000m,
42.00000000000m,
42.000000000000m,
42.0000000000000m,
42.00000000000000m,
42.000000000000000m,
42.0000000000000000m,
42.00000000000000000m,
42.000000000000000000m,
42.0000000000000000000m,
42.00000000000000000000m,
42.000000000000000000000m,
42.0000000000000000000000m,
42.00000000000000000000000m,
42.000000000000000000000000m,
42.0000000000000000000000000m,
42.00000000000000000000000000m,
42.000000000000000000000000000m,
};
foreach (var m in arr)
{
Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
"{0,-32}{1,-20:R}{2:X8}", m, (double)m, m.GetHashCode()
));
}
Console.WriteLine("Funny consequences:");
var h1 = new HashSet<decimal>(arr);
Console.WriteLine(h1.Count);
var h2 = new HashSet<double>(arr.Select(m => (double)m));
Console.WriteLine(h2.Count);
}
Run Code Online (Sandbox Code Playgroud)
给出以下"有趣"(显然不正确)的输出:
42 42 40450000 42.0 42 40450000 42.00 42 40450000 …
为了说明我的问题,请考虑这些简单的例子(C#):
object reference = new StringBuilder();
object box = 42;
object unset = null;
// CASE ONE: bad reference conversions (CIL instrcution 0x74 'castclass')
try
{
string s = (string)reference;
}
catch (InvalidCastException ice)
{
Console.WriteLine(ice.Message); // Unable to cast object of type 'System.Text.StringBuilder' to type 'System.String'.
}
try
{
string s = (string)box;
}
catch (InvalidCastException ice)
{
Console.WriteLine(ice.Message); // Unable to cast object of type 'System.Int32' to type 'System.String'.
}
// CASE TWO: bad unboxing conversions (CIL instrcution …Run Code Online (Sandbox Code Playgroud) 我认为这看起来像C#编译器中的一个错误.
考虑这段代码(在方法内):
const long dividend = long.MinValue;
const long divisor = -1L;
Console.WriteLine(dividend % divisor);
Run Code Online (Sandbox Code Playgroud)
它编译时没有错误(或警告).好像是一个bug.运行时,0在控制台上打印.
然后没有const,代码:
long dividend = long.MinValue;
long divisor = -1L;
Console.WriteLine(dividend % divisor);
Run Code Online (Sandbox Code Playgroud)
当它运行时,它正确地导致OverflowException被抛出.
C#语言规范专门提到了这个案例,并说System.OverflowException将抛出一个.它不依赖于上下文checked或unchecked似乎(也是与余数运算符的编译时常量操作数的错误与checked和相同unchecked).
int(System.Int32),而不仅仅是long(System.Int64)发生同样的错误.
相比之下,编译器处理dividend / divisor与const操作数比要好得多dividend % divisor.
我的问题:
我是对的,这是一个错误吗?如果是,它是一个众所周知的错误,他们不希望修复(因为向后兼容性,即使使用% -1编译时常量相当愚蠢-1)?或者我们应该报告它,以便他们可以在即将推出的C#编译器版本中修复它?
只是奇怪的是,当我反思所有类型时,我偶然发现了好奇心来检查其他东西.
为什么System.__ComObject集会的阶级mscorlib.dll(有时?)声称是公开的,而事实上它似乎是非公开的?如果我在一个简单的C#控制台应用程序中运行以下代码:
var t = Type.GetType("System.__ComObject");
Console.WriteLine(t.IsPublic); // "True" ?!
Console.WriteLine(t.IsVisible); // "False"
Run Code Online (Sandbox Code Playgroud)
输出似乎有冲突.非嵌套类型(t.IsNested为false)应为IsPublic和提供相同的真值IsVisible.当我看到装配时,IL DASM我看到:
.class private auto ansi beforefieldinit System.__ComObject
extends System.MarshalByRefObject
{
} // end of class System.__ComObject
Run Code Online (Sandbox Code Playgroud)
对我来说,它看起来非常像非公开类,这些对应于下面的C#代码:
namespace System
{
// not public
internal class __ComObject : MarshalByRefObject
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
当我比较其他类型的具有类似的名称,System.__Canon以及类似IL改性剂,既IsPublic与IsVisible预期返回false.
有谁知道为什么(和什么时候)Type.GetType("System.__ComObject").IsPublic给出了真实的?
为了避免在搜索已知类型的属性时使用过时的非泛型语法,通常会使用System.Reflection.CustomAttributeExtensions类中的扩展方法(从.NET 4.5开始).
但是,如果在重写方法的返回参数(或重写的属性/索引器的访问者)上搜索属性,则这似乎会失败.
我正在使用.NET 4.6.1体验这一点.
简单复制(完整):
using System;
using System.Reflection;
namespace ReflectionTrouble
{
class B
{
//[return: MyMark("In base class")] // uncommenting does not help
public virtual int M() => 0;
}
class C : B
{
[return: MyMark("In inheriting class")] // commenting away attribute does not help
public override int M() => -1;
}
[AttributeUsage(AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = false)] // commenting away AttributeUsage does not help
sealed class MyMarkAttribute : Attribute
{ …Run Code Online (Sandbox Code Playgroud) 当我使用这段代码时:
var ri = new RegionInfo("us");
var nativeName = ri.NativeName; // ?? ??????? ????
Run Code Online (Sandbox Code Playgroud)
nativeName那么为什么是弦乐"?? ??????? ????"(在切罗基)?
如果我改为new RegionInfo("US")(只有差异,资本US),我会改为"United States".
我做知道的首选使用的RegionInfo是给特定的文化信息字符串,例如:
new RegionInfo("en-US")
new RegionInfo("chr-Cher-US")
Run Code Online (Sandbox Code Playgroud)
等等,这是有效的.但是,只有当我使用小写时,为什么切诺基比英语更喜欢us?
(见于Windows 10(版本1803"2018年4月更新"),.NET Framework 4.7.2.)
更新:即使在同一台机器上,这也不一致.例如,我尝试打开PowerShell很多次,每次粘贴[System.Globalization.RegionInfo]'US'它.好像很长一段时间,PowerShell的所有实例都始终给出相同的结果.但过了一会儿,PowerShell的实例会产生相反的结果.这是两个窗口的屏幕截图,一个窗口始终有一个窗口,另一个窗口NativeName始终具有相反的窗口.因此必须有一些非确定性的决定(套管无差异):
我有一种情况,我喜欢编译器的行为解释.给出一点代码:
interface IFoo<T>
{
T Get();
}
class FooGetter : IFoo<int>
{
public int Get()
{
return 42;
}
}
Run Code Online (Sandbox Code Playgroud)
以下编译并运行:
static class FooGetterGetter
{
public static IFoo<T> Get<T>()
{
return (IFoo<T>)new FooGetter();
}
}
Run Code Online (Sandbox Code Playgroud)
如果我们更改Foo类的签名并添加sealed关键字:
sealed class FooGetter : IFoo<int> // etc
Run Code Online (Sandbox Code Playgroud)
然后我在以下行得到编译器错误:
return (IFoo<T>)new FooGetter();
Run Code Online (Sandbox Code Playgroud)
的:
无法将类型'MyNamespace.FooGetter'转换为'MyNamespace.IFoo <T>'
有人可以解释sealed关键字的问题吗?这是针对Visual Studio 2010中的.NET 4项目的C#4.
更新:有趣的是,当我想知道为什么以下代码在sealed应用时修复它时,我偶然发现了这部分行为:
return (IFoo<T>)(IFoo<int>)new FooGetter();
Run Code Online (Sandbox Code Playgroud)
更新:只是为了澄清,当T请求的类型T与具体类型使用的类型相同时,它都运行良好.如果类型不同,则转换在运行时失败,例如:
无法将"MyNamespace.StringFoo"类型的对象强制转换为"MyNamespace.IFoo"1 [System.Int32]'
在上面的示例中,StringFoo : IFoo<string>调用者要求获取 …
众所周知,在C#中,可以指定自定义属性规范的目标,如示例中所示
[method: SomeDecoration]
[return: SomeOtherMark]
int MyMethod();
Run Code Online (Sandbox Code Playgroud)
其中"targets" method:并return:帮助指定属性所属的代码中的哪个元素.
根据C#语言规范,存在以下属性目标:
assemblymodulefieldeventmethodparampropertyreturntype其中一些,如同field,总是多余的,因为它总是很清楚属性"坐在"而没有指定它们.
但是确实存在(至少在Visual C#的实现和版本中我在这里)一个额外的属性目标,即:
typevar例如在代码中允许的
class MyGenericCollection<[typevar: HereYouSee] TItem> // legal
{
}
Run Code Online (Sandbox Code Playgroud)
属性目标typevar,就像field其他人一样,永远不需要.
我的问题:有没有人知道typevar:规范或文档中没有提到的历史原因?当编写2.0版本的C#语言规范时,这个被遗忘了吗?或者,如果不是疏忽,为什么要实施呢?
如果标题不完全不言自明,这里的代码让我困惑:
public interface IFoo<T>
{
}
public class MyClass : IFoo<MyClass.NestedInMyClass>
{
private class NestedInMyClass
{
}
}
Run Code Online (Sandbox Code Playgroud)
我很惊讶这个编译没有错误.感觉就像我暴露了一种private类型.这不应该是违法的吗?
也许你的回答只是"没有规则反对,所以为什么不行呢?" MyClass.NestedInMyClass即使在"范围"中也许同样令人惊讶.如果我删除了MyClass.资格,它将无法编译.
(如果我改为IFoo<>通用类,它应该成为基类MyClass,这是非法的,因为基类型必须至少与类型本身一样可访问.)
我尝试使用Visual Studio 2010的C#4编译器.
通过反射,在枚举类型的字段中查看,我惊讶地发现,保留枚举的特定实例的实际值的"支持"实例字段不是private,正如我所想的那样,但是public.它也不readonly是.(IsPublic是的,IsInitOnly假的.)
许多人认为.NET类型系统中的"可变"值类型"邪恶",那么为什么枚举类型(例如从C#代码创建)就是这样?
现在,事实证明,C#编译器有某种魔法否认公共实例字段的存在(但见下文),但在例如PowerShell中你可以这样做:
prompt> $d = [DayOfWeek]::Thursday
prompt> $d
Thursday
prompt> $d.value__ = 6
prompt> $d
Saturday
Run Code Online (Sandbox Code Playgroud)
该字段value__可以写入.
现在,要在C#中执行此操作,我必须使用,dynamic因为看起来使用正常的编译时成员绑定,C#假装public实例字段不存在.当然要使用dynamic,我们将不得不使用枚举值的装箱.
这是一个C#代码示例:
// create a single box for all of this example
Enum box = DayOfWeek.Thursday;
// add box to a hash set
var hs = new HashSet<Enum> { box, };
// make a dynamic reference to the same …Run Code Online (Sandbox Code Playgroud) c# ×10
.net ×6
cil ×2
reflection ×2
attributes ×1
casing ×1
clr ×1
compiler-bug ×1
decimal ×1
enums ×1
generics ×1
immutability ×1
modulus ×1
operators ×1
powershell ×1
regioninfo ×1
unboxing ×1