我最近正在使用一个DateTime对象,并写了这样的东西:
DateTime dt = DateTime.Now;
dt.AddDays(1);
return dt; // still today's date! WTF?
AddDays()的智能感知文档说它在日期后添加了一天,但它并没有这样做——它实际上返回了一个添加了一天的日期,所以你必须这样写:
DateTime dt = DateTime.Now;
dt = dt.AddDays(1);
return dt; // tomorrow's date
这个问题以前已经困扰过我很多次了,所以我认为将最糟糕的c#陷阱分类会很有用。
合同在流。阅读是我见过很多人被绊倒的东西:
// Read 8 bytes and turn them into a ulong
byte[] data = new byte[8];
stream.Read(data, 0, 8); // <-- WRONG!
ulong data = BitConverter.ToUInt64(data);
这是错误的原因是流。Read最多读取指定的字节数,但完全可以只读取1个字节,即使在流结束前还有7个字节可用。
它看起来与Stream如此相似,这并没有什么帮助。如果没有异常返回,则保证已写入所有字节。上面的代码几乎一直都能工作,这也没有什么帮助。当然,没有现成的、方便的方法来正确地读取N个字节也无济于事。
所以,为了堵住这个漏洞,提高人们的意识,这里有一个正确的方法:
/// <summary>
/// Attempts to fill the buffer with the specified number of bytes from the
/// stream. If there are fewer bytes left in the stream than requested then
/// all available bytes will be read into the buffer.
/// </summary>
/// <param name="stream">Stream to read from.</param>
/// <param name="buffer">Buffer to write the bytes to.</param>
/// <param name="offset">Offset at which to write the first byte read from
/// the stream.</param>
/// <param name="length">Number of bytes to read from the stream.</param>
/// <returns>Number of bytes read from the stream into buffer. This may be
/// less than requested, but only if the stream ended before the
/// required number of bytes were read.</returns>
public static int FillBuffer(this Stream stream,
byte[] buffer, int offset, int length)
{
int totalRead = 0;
while (length > 0)
{
var read = stream.Read(buffer, offset, length);
if (read == 0)
return totalRead;
offset += read;
length -= read;
totalRead += read;
}
return totalRead;
}
/// <summary>
/// Attempts to read the specified number of bytes from the stream. If
/// there are fewer bytes left before the end of the stream, a shorter
/// (possibly empty) array is returned.
/// </summary>
/// <param name="stream">Stream to read from.</param>
/// <param name="length">Number of bytes to read from the stream.</param>
public static byte[] Read(this Stream stream, int length)
{
byte[] buf = new byte[length];
int read = stream.FillBuffer(buf, 0, length);
if (read < length)
Array.Resize(ref buf, read);
return buf;
}
对于C/ c++程序员来说,过渡到c#是很自然的事情。然而,我个人遇到的最大的问题(以及其他人在做同样的转换时遇到的问题)是没有完全理解c#中类和结构之间的区别。
在c++中,类和结构是相同的;它们只在默认可见性上有所不同,其中类默认为私有可见性,结构默认为公共可见性。在c++中,这个类定义
class A
{
public:
int i;
};
在功能上等价于此结构定义。
struct A
{
int i;
};
然而,在c#中,类是引用类型,而结构是值类型。这在(1)决定何时使用一个而不是另一个,(2)测试对象的相等性,(3)性能(例如,装箱/拆箱)等方面产生了很大的差异。
网络上有各种各样的信息与两者之间的差异有关(例如,这里)。我强烈建议任何想要过渡到c#的人至少要了解这些差异及其含义。
Linq2SQL:接口成员的映射[…]不支持。
如果对实现接口的对象执行Linq2Sql查询,则会得到非常奇怪的行为。假设你有一个类MyClass,它实现了一个接口IHasDescription,这样:
public interface IHasDescription {
string Description { get; set; }
}
public partial class MyClass : IHasDescription { }
(MyClass的另一半是一个Linq2Sql生成的类,包括属性Description。)
现在你写一些代码(这通常发生在泛型方法中):
public static T GetByDescription<T>(System.Data.Linq.Table<T> table, string desc)
where T : class, IHasDescription {
return table.Where(t => t.Description == desc).FirstOrDefault();
}
编译正常-但你会得到一个运行时错误:
NotSupportedException: The mapping of interface member IHasDescription.Description is not supported.
现在该怎么办呢?好吧,这真的很明显:只需将==更改为.Equals(),这样:
return table.Where(t => t.Description.Equals(desc)).FirstOrDefault();
现在一切都好了!
在这里看到的。