请考虑以下代码:
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#5中,foreach语句的闭包语义(当迭代变量被匿名函数"捕获"或"关闭"时)发生了着名的变化(链接到该主题的线程).
问题:是否打算更改指针类型数组?
为什么我想问的原因是,一个的"扩张" foreach的语句已被改写,由于技术原因(我们不能使用Current的财产System.Collections.IEnumerator,因为该物业已声明的类型object是不兼容的指针类型)相比foreach于其他藏品.C#语言规范中的相关部分,"指针数组",在5.0版本中说:
foreach (V v in x) EMBEDDED-STATEMENT
Run Code Online (Sandbox Code Playgroud)
扩展到:
{
T[,,…,] a = x;
V v;
for (int i0 = a.GetLowerBound(0); i0 <= a.GetUpperBound(0); i0++)
for (int i1 = a.GetLowerBound(1); i1 <= a.GetUpperBound(1); i1++)
…
for (int in = a.GetLowerBound(N); iN <= a.GetUpperBound(n); iN++) {
v = (V)a.GetValue(i0,i1,…,iN);
EMBEDDED-STATEMENT
}
}
Run Code Online (Sandbox Code Playgroud)
我们注意到声明V v;在所有for循环之外.因此看起来闭包语义仍然是"旧的"C#4风格,"循环变量被重用,循环变量相对于循环变为"外部".
为了说明我在说什么,请考虑这个完整的C#5计划:
using …Run Code Online (Sandbox Code Playgroud) 我的项目在VS 2013中编译,但不在VS 2015中编译.下面的代码重现了编译问题.Validator类实际上是在第三方程序集中,因此我无法更改实现.require类是本地类,但我不想更改实现,因为我将不得不更改许多验证逻辑.下面是在VS 2015中无法编译的代码.
public abstract class Validator<T> : Validator
{
public override void DoValidate(object objectToValidate)
{
}
protected abstract void DoValidate(T objectToValidate);
}
public abstract class Validator
{
public abstract void DoValidate(object objectToValidate);
}
public abstract class ValidatorBase<T> : Validator<T>
{
protected override void DoValidate(T objectToValidate)
{
}
}
public class Required : ValidatorBase<object>
{
}
Run Code Online (Sandbox Code Playgroud)
这个编译问题有解决方法吗?任何帮助,将不胜感激.
错误:
Severity Code Description Project File Line Error CS0534 'Required' does not implement inherited abstract member 'Validator<object>.DoValidate(object)' Program.cs 38
我已经尝试搜索SO以获得答案并偶然发现类似的问题,但我无法使用它们来解决我的问题,所以请尽量不要将其标记为重复.让我们继续谈谈真正的交易:
我有一个通用库,用于标准化实体框架数据库的第一个模型.这些是我创建的泛型类:
public abstract class GenericLookupModel : IActive, ICreated, IModified, IIdentity, IStringValue
{
public bool is_active { get; set; }
public string value { get; set; }
public string description { get; set; }
public DateTime created_on { get; set; }
public string created_by { get; set; }
public DateTime modified_on { get; set; }
public string modified_by { get; set; }
public int id {get;set;}
public void SetCreated(string creator = "SYSTEM")
{
created_by = creator;
created_on = DateTime.Now;
} …Run Code Online (Sandbox Code Playgroud) 当然,C#支持一维和多维数组,并且支持数组的数组。众所周知,如果在数组数组中,内部数组类型与外部数组具有不同的等级(维数),则 C# 语言和 .NET 运行时在类型中给出括号的顺序上存在分歧姓名。尤其:
typeof(string[][,]).Name == "String[,][]"
Run Code Online (Sandbox Code Playgroud)
和:
typeof(string[,][]).Name == "String[][,]"
Run Code Online (Sandbox Code Playgroud)
所以可能会出现一些混乱,但它确实有效。
以下是此类类型的正确用法:
static void Foo1(string[,][] a) {
//read:
string[] entry = a[7, 8];
//write:
a[7, 8] = new string[] { "alfa", "bravo", "charlie", "delta", };
}
static void Bar1(string[][,] a) {
//read:
string[,] entry = a[9];
//write:
a[9] = new string[,] { { "echo", "foxtrot", }, { "golf", "hotel", }, { "india", "juliett", }, };
}
Run Code Online (Sandbox Code Playgroud)
读者可以自己验证它是否可以编译并且可以工作(当然必须传入足够大的数组)。
现在,当我们尝试将上述内容与可空引用类型结合起来时,就会出现严重的问题,正如 C# 8(从 2019 年起)以来的 C# 中所存在的那样。至少使用我这里的编译器实现(最新版本的 Visual Studio 2022)。也就是说,如果我做这个轻微的修改:
// …Run Code Online (Sandbox Code Playgroud) c# jagged-arrays compiler-bug arrayofarrays nullable-reference-types
通常,人们会期望并希望首先取消装箱值类型然后执行某种值类型转换为另一种值类型需要两次转换.这是一个例子:
// create boxed int
IFormattable box = 42; // box.GetType() == typeof(int)
// unbox and narrow
short x1 = (short)box; // fails runtime :-)
short x2 = (short)(int)box; // OK
// unbox and make unsigned
uint y1 = (uint)box; // fails runtime :-)
uint y2 = (uint)(int)box; // OK
// unbox and widen
long z1 = (long)box; // fails runtime :-)
long z2 = (long)(int)box; // OK (cast to long could be made implicit)
Run Code Online (Sandbox Code Playgroud)
正如你从我的表情中看到的那样,如果我只使用一个演员,我很高兴这些转换会失败.毕竟,尝试在一次操作中将值类型拆分为不同的值类型可能是编码错误.
(IFormattable …
我有一个泛型类,其子类提供特定类型.
public abstract class GenericBase<T>
where T:Interface1
{
}
Run Code Online (Sandbox Code Playgroud)
我将泛型与特定实现子类化:
public class Customer:
GenericBase<Type1>
Run Code Online (Sandbox Code Playgroud)
(Type1实施Interface1).
我有另一个抽象基类,它引用了这个:
protected GenericBase<Interface1> genericInstance;
Run Code Online (Sandbox Code Playgroud)
最后,当我尝试将genericInstance分配给基类的实例时,它给了我一个编译器错误,说它"无法隐式地将Customer转换为GenericBase <Interface1>".
base.genericInstance = new Customer(); //Compiler error
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我会得到这个错误,如果Customer是一个子类型GenericBase<Type1>和Type1实现Interface1.是不是Customer有效的一种类型GenericBase<Interface1>,如果它是一个子类GenericBase<Type1>?
我想我在这里误解了一些关于泛型的东西; 有没有办法允许这种行为?
我刚刚升级到VS2015.1并且在尝试编译我的一个项目时遇到了编译器崩溃.如果您将以下repo代码放在控制台应用程序中(并添加对moq.dll的引用),则第12行中的代码会使我的编译器崩溃.这似乎发生在Roslyn lamdba重写调用期间.
using System.Collections.Generic;
using System.Linq;
using Moq;
namespace RoslynError
{
class Program
{
static void Main(string[] args)
{
var mockRepo = new MockRepository(MockBehavior.Strict);
var obj = mockRepo.OneOf<DTO>(x => x.Value == (OptionEnum?)null);
}
}
class DTO
{
public DTO(OptionEnum? enumVal)
{
Value = enumVal;
}
public OptionEnum? Value;
}
enum OptionEnum
{
NotSpecified
}
}
Run Code Online (Sandbox Code Playgroud)
有谁知道崩溃发生的原因?
直到今天,我(隐式)假设当我输出一个BigIntegervia参数无效(重写)实例方法时BigInteger.ToString(),返回字符串将包含我的"大"整数的完整和精确的十进制表示.
但在MSDN文档页面上,我读到:
"在大多数情况下,ToString方法支持50个十进制数字的精度.也就是说,如果BigInteger值超过50位,输出字符串中只保留50个最高有效数字;所有其他数字都替换为零.但是,BigInteger支持"R"标准格式说明符,用于往返数值.由ToString(String)方法返回的带有"R"格式字符串的字符串保留整个BigInteger值,然后可以使用Parse或TryParse方法恢复其原始值而不会丢失任何数据"._
但是,我还没有找到一个myBigInt.ToString()与之不同的例子myBigInt.ToString("R").在我的框架版本(.NET 4.0 SP1)中,上述页面中的备注示例并未提供示例.(此外"G"和"R"似乎是等效BigInteger).
假设无参数ToString()给出整数的完整十进制扩展是否安全?他们是否改变了框架行为,或者上面提到的示例代码总是错误的?
注意:在我写完这个之后,SO向我展示了这个"类似的问题"2984184,但是我仍然在提交我的问题,因为2984184的答案并没有真正规避零参数的ToString()工作原理.
由自己编辑:
ToString(String)当我的问题(主要是)关于ToString()过载时,我在MSDN 上链接过载有点不合适.因此,另请参阅MSDN,BigInteger.ToString()其中提到了50位数限制,但未提供超过50位数的示例.
实例属性的文档Type.IsConstructedGenericType不清楚或具有误导性.
我尝试了以下代码来查找此属性和相关属性的实际行为:
// create list of types to use later in a Dictionary<,>
var li = new List<Type>();
// two concrete types:
li.Add(typeof(int));
li.Add(typeof(string));
// the two type parameters from Dictionary<,>
li.Add(typeof(Dictionary<,>).GetGenericArguments()[0]);
li.Add(typeof(Dictionary<,>).GetGenericArguments()[1]);
// two unrelated type parameters
li.Add(typeof(Func<,,,>).GetGenericArguments()[1]);
li.Add(typeof(EventHandler<>).GetGenericArguments()[0]);
// run through all possibilities
foreach (var first in li)
{
foreach (var second in li)
{
var t = typeof(Dictionary<,>).MakeGenericType(first, second);
Console.WriteLine(t);
Console.WriteLine(t.IsGenericTypeDefinition);
Console.WriteLine(t.IsConstructedGenericType);
Console.WriteLine(t.ContainsGenericParameters);
}
}
Run Code Online (Sandbox Code Playgroud)
代码贯穿由36种类型组成的笛卡尔积t.
结果:对于32种类型(所有,但4个组合Dictionary<int, int>,Dictionary<int, string>, …
c# ×10
.net ×3
generics ×3
asp.net-mvc ×1
biginteger ×1
boxing ×1
c#-5.0 ×1
closures ×1
comparison ×1
compiler-bug ×1
crash ×1
enums ×1
foreach ×1
lambda ×1
nullable ×1
pointers ×1
reflection ×1
roslyn ×1
subclass ×1
type-safety ×1
types ×1