你在C#或.NET中看到的最奇怪的角落是什么?

时间:2008-10-11 19:30:45

标签: c# .net

我收集了几个角落案例和brain teasers,并且总是希望听到更多。该页面仅涵盖C#语言位和bobs,但我也发现核心.NET的东西也很有趣。例如,这是一个不在页面上,但我觉得不可思议的一个:

string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));

我希望打印False - 毕竟,“new”(带引用类型)总是创建一个新对象,不是吗? C#和CLI的规范都表明它应该。好吧,不是在这种特殊情况下。它打印True,并在我测试过的每个版本的框架上完成。 (我没有在Mono上尝试过,诚然......)

为了清楚起见,这只是我正在寻找的那种事情的一个例子 - 我并不是特别想要讨论/解释这种奇怪的事情。 (它与正常的字符串实习不同;特别是,当调用构造函数时,通常不会发生字符串实习。)我真的要求类似的奇怪行为。

其他任何宝石潜伏在那里?

37 个答案:

答案 0 :(得分:394)

我想我以前给你看了这个,但我喜欢这里的乐趣 - 这需要一些调试来追踪! (原始代码显然更加复杂和微妙......)

    static void Foo<T>() where T : new()
    {
        T t = new T();
        Console.WriteLine(t.ToString()); // works fine
        Console.WriteLine(t.GetHashCode()); // works fine
        Console.WriteLine(t.Equals(t)); // works fine

        // so it looks like an object and smells like an object...

        // but this throws a NullReferenceException...
        Console.WriteLine(t.GetType());
    }

那是什么T ...

答案:任何Nullable<T> - 例如int?。除了GetType()之外,所有方法都被覆盖;所以它被转换(加框)到object(因此为null)来调用object.GetType()...调用null; -p


更新:情节变浓...... Ayende Rahien扔了一个similar challenge on his blog,但是where T : class, new()

private static void Main() {
    CanThisHappen<MyFunnyType>();
}

public static void CanThisHappen<T>() where T : class, new() {
    var instance = new T(); // new() on a ref-type; should be non-null, then
    Debug.Assert(instance != null, "How did we break the CLR?");
}

但它可以被击败!使用像远程处理这样的间接使用的相同方向;警告 - 以下是纯邪恶

class MyFunnyProxyAttribute : ProxyAttribute {
    public override MarshalByRefObject CreateInstance(Type serverType) {
        return null;
    }
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }

完成此操作后,new()调用将重定向到代理(MyFunnyProxyAttribute),后者将返回null。现在去洗你的眼睛!

答案 1 :(得分:216)

银行家的四舍五入。

这不是编译器错误或故障,而是一个奇怪的角落案例......

.Net Framework使用一种称为Banker's Rounding的方案或舍入。

在银行家的舍入中,0.5数字四舍五入到最接近的偶数,所以

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

这可能导致基于更为人熟知的Round-Half-Up四舍五入的财务计算中的一些意外错误。

Visual Basic也是如此。

答案 2 :(得分:176)

如果调用Rec(0)(不在调试器下),此函数将执行什么操作?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

答案:

  • 在32位JIT上,它应该导致StackOverflowException
  • 在64位JIT上,它应该将所有数字打印到int.MaxValue

这是因为the 64-bit JIT compiler applies tail call optimisation,而32位JIT没有。

不幸的是我没有64位机器可以验证这一点,但该方法确实满足尾部调用优化的所有条件。如果有人有,我有兴趣看看它是否属实。

答案 3 :(得分:112)

分配这个!


这是我喜欢在聚会上提出的问题(这可能是我不再受邀的原因):

你可以编译下面这段代码吗?

    public void Foo()
    {
        this = new Teaser();
    }

一个简单的骗子可能是:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

但真正的解决方案是:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

因此,值得知道的是,值类型(结构)可以重新分配其this变量。

答案 4 :(得分:100)

几年前,在制定忠诚计划时,我们遇到了向客户提供的积分问题。该问题与将double转换/转换为int有关。

在下面的代码中:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

i1 == i2

事实证明,i1!= i2。 由于Convert和cast运算符中的舍入策略不同,实际值为:

i1 == 14
i2 == 13

最好调用Math.Ceiling()或Math.Floor()(或MidlingRounding符合我们要求的Math.Round)

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

答案 5 :(得分:74)

即使存在枚举函数重载,它们也应该使0为整数。

我知道C#核心团队的理由是将0映射到枚举,但是,它仍然不像它应该的那样正交。来自Npgsql的示例。

测试示例:

namespace Craft
{
    enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };


   class Mate
    {
        static void Main(string[] args)
        {

            JustTest(Symbol.Alpha); // enum
            JustTest(0); // why enum
            JustTest((int)0); // why still enum

            int i = 0;

            JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version

            JustTest(i); // it's ok from down here and below
            JustTest(1);
            JustTest("string");
            JustTest(Guid.NewGuid());
            JustTest(new DataTable());

            Console.ReadLine();
        }

        static void JustTest(Symbol a)
        {
            Console.WriteLine("Enum");
        }

        static void JustTest(object o)
        {
            Console.WriteLine("Object");
        }
    }
}

答案 6 :(得分:67)

这是迄今为止我见过的最不寻常的事情之一(当然除了这里的那些!):

public class Turtle<T> where T : Turtle<T>
{
}

它允许你声明它但没有实际用途,因为它总是会要求你用另一只海龟包裹你在中心的任何课程。

[笑话]我猜这是乌龟一路下来...... [/笑话]

答案 7 :(得分:65)

这是我最近才发现的......

interface IFoo
{
   string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

以上看起来很疯狂,但实际上是合法的。不,真的(虽然我错过了一个关键部分,但它不是任何东西hacky喜欢“添加一个名为IFoo的类”或“添加一个using别名来指向一个类的IFoo”。

看看你能否找出原因,然后:Who says you can’t instantiate an interface?

答案 8 :(得分:56)

布尔值何时既不是真也不是假?

Bill发现你可以破解一个布尔值,这样如果A为True且B为True,则(A和B)为False。

Hacked Booleans

答案 9 :(得分:47)

我到达派对有点迟了,但我已经 3 4 5:

  1. 如果您在尚未加载/显示的控件上轮询InvokeRequired,它将显示为false - 如果您尝试从另一个线程(the solution更改为参考this.Handle在控件的创建者。)

  2. 另一个绊倒我的是给定一个装配:

    enum MyEnum
    {
        Red,
        Blue,
    }
    

    如果你在另一个程序集中计算MyEnum.Red.ToString(),并且有时候有人重新编译你的枚举:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

    在运行时,你会得到“黑色”。

  3. 我有一个带有一些方便常量的共享程序集。我的前任留下了一堆丑陋的get-only属性,我以为我会摆脱杂乱而只是使用公共const。当VS将它们编译为它们的值而不是引用时,我有点惊讶。

  4. 如果从另一个程序集实现一个接口的新方法,但是重建引用该程序集的旧版本,则会得到一个TypeLoadException(没有'NewMethod'的实现),即使你实施了它(请参阅here)。

  5. 字典&lt;,&gt;:“未定义项目的返回顺序”。这是可怕的,因为它有时可能会咬你,但是会工作别人,如果你只是盲目地认为词典会发挥得很好(“为什么不应该呢?我想,List会做“),在你最终开始质疑你的假设之前,你真的必须先了解它。

答案 10 :(得分:33)

VB.NET,nullables和三元运算符:

Dim i As Integer? = If(True, Nothing, 5)

我花了一些时间来调试,因为我希望i包含Nothing

我真的含有什么? 0

这是令人惊讶但实际上是“正确”的行为:VB.NET中的Nothing与CLR中的null不完全相同:Nothing可以表示nulldefault(T)表示值类型T,具体取决于上下文。在上述情况下,If推断IntegerNothing5的常见类型,因此,在这种情况下,Nothing表示0

答案 11 :(得分:28)

我找到了第二个非常奇怪的角落案例,远远超过了我的第一个案例。

String.Equals Method(String,String,StringComparison)实际上不是副作用。

我正在处理一段代码,这些代码在某个函数的顶部单独排在一行:

stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);

删除该行会导致程序中其他位置的堆栈溢出。

代码原来是为了本质上是一个BeforeAssemblyLoad事件而安装一个处理程序并尝试做

if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
    assemblyfilename = "someparticular_modified.dll";
}

到现在为止我不应该告诉你。在字符串比较中使用之前未使用过的文化会导致程序集加载。 InvariantCulture也不例外。

答案 12 :(得分:20)

以下是如何创建一个结构的示例,该结构导致错误消息“尝试读取或写入受保护的内存。这通常表示其他内存已损坏”。 成功与失败之间的区别非常微妙。

以下单元测试证明了这个问题。

看看你能解决出了什么问题。

    [Test]
    public void Test()
    {
        var bar = new MyClass
        {
            Foo = 500
        };
        bar.Foo += 500;

        Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
    }

    private class MyClass
    {
        public MyStruct? Foo { get; set; }
    }

    private struct MyStruct
    {
        public decimal Amount { get; private set; }

        public MyStruct(decimal amount) : this()
        {
            Amount = amount;
        }

        public static MyStruct operator +(MyStruct x, MyStruct y)
        {
            return new MyStruct(x.Amount + y.Amount);
        }

        public static MyStruct operator +(MyStruct x, decimal y)
        {
            return new MyStruct(x.Amount + y);
        }

        public static implicit operator MyStruct(int value)
        {
            return new MyStruct(value);
        }

        public static implicit operator MyStruct(decimal value)
        {
            return new MyStruct(value);
        }
    }

答案 13 :(得分:18)

C#支持数组和列表之间的转换,只要数组不是多维的,并且类型之间存在继承关系,类型是引用类型

object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;

// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };

请注意,这不起作用:

object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2;            // Error: Cannot convert type 'object[]' to 'int[]'

答案 14 :(得分:15)

这是我偶然遇到的最奇怪的事情:

public class DummyObject
{
    public override string ToString()
    {
        return null;
    }
}

使用如下:

DummyObject obj = new DummyObject();
Console.WriteLine("The text: " + obj.GetType() + " is " + obj);

将抛出NullReferenceException。结果是C#编译器将多个添加内容编译为对String.Concat(object[])的调用。在.NET 4之前,在Concat的重载中存在一个错误,其中对象被检查为null,但不是ToString()的结果:

object obj2 = args[i];
string text = (obj2 != null) ? obj2.ToString() : string.Empty;
// if obj2 is non-null, but obj2.ToString() returns null, then text==null
int length = text.Length;

这是ECMA-334§14.7.4的错误:

  

当一个或两个操作数的类型为string时,binary +运算符执行字符串连接。如果字符串连接的操作数是null,则替换空字符串。否则,通过调用从类型ToString继承的虚拟object方法,将任何非字符串操作数转换为其字符串表示形式。 如果ToString返回null,则会替换空字符串。

答案 15 :(得分:12)

有趣 - 当我第一次看到我认为它是C#编译器正在检查的东西时,但即使你直接发射IL以消除任何干扰的机会它仍然会发生,这意味着它真的是{{1正在进行检查的操作码。

newobj

如果您检查var method = new DynamicMethod("Test", null, null); var il = method.GetILGenerator(); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Newarr, typeof(char)); il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) })); il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Newarr, typeof(char)); il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) })); il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals")); il.Emit(OpCodes.Box, typeof(bool)); il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) })); il.Emit(OpCodes.Ret); method.Invoke(null, null); ,它也等同于true,这意味着此操作码必须对实习空字符串具有特殊行为。

答案 16 :(得分:10)

今天刚刚发现一件好事:

public class Base
{
   public virtual void Initialize(dynamic stuff) { 
   //...
   }
}
public class Derived:Base
{
   public override void Initialize(dynamic stuff) {
   base.Initialize(stuff);
   //...
   }
}

这会抛出编译错误。

对方法'Initialize'的调用需要动态调度,但不能因为它是基本访问表达式的一部分。考虑转换动态参数或取消基本访问。

如果我写base.Initialize(东西作为对象);它完美无缺,但这似乎是一个“神奇的词”,因为它完全相同,所有东西仍然被认为是动态的......

答案 17 :(得分:10)

C#辅助功能Puzzler


以下派生类正在从其基类访问私有字段,编译器默默地向另一方查看:

public class Derived : Base
{
    public int BrokenAccess()
    {
        return base.m_basePrivateField;
    }
}

该领域确实是私人的:

private int m_basePrivateField = 0;

注意猜测我们如何编译这样的代码?

答案


诀窍是将Derived声明为Base的内部类:

public class Base
{
    private int m_basePrivateField = 0;

    public class Derived : Base
    {
        public int BrokenAccess()
        {
            return base.m_basePrivateField;
        }
    }
}

内部类可以完全访问外部类成员。在这种情况下,内部类也恰好从外部类派生。这使我们能够“打破”私人成员的封装。

答案 18 :(得分:10)

如果您的泛型类具有可能根据类型参数而变得模糊的方法,该怎么办?我最近遇到这种情况写了一本双向字典。我想编写对称的Get()方法,这些方法将返回与传递的任何参数相反的方法。像这样:

class TwoWayRelationship<T1, T2>
{
    public T2 Get(T1 key) { /* ... */ }
    public T1 Get(T2 key) { /* ... */ }
}

如果您创建T1T2不同类型的实例,那么一切都很好:

var r1 = new TwoWayRelationship<int, string>();
r1.Get(1);
r1.Get("a");

但是如果T1T2相同(并且可能是一个是另一个的子类),那就是编译错误:

var r2 = new TwoWayRelationship<int, int>();
r2.Get(1);  // "The call is ambiguous..."

有趣的是,第二种情况下的所有其他方法仍然可用;它只调用现在不明确的方法导致编译器错误。有趣的案例,如果有点不太可能和模糊。

答案 19 :(得分:10)

Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

输出“尝试读取受保护的内存。这表示其他内存已损坏。”

答案 20 :(得分:10)

PropertyInfo.SetValue()可以为枚举分配int,为可为空的int分配int,为可为空的枚举分配枚举,但​​不为可为空的枚举分配int。

enumProperty.SetValue(obj, 1, null); //works
nullableIntProperty.SetValue(obj, 1, null); //works
nullableEnumProperty.SetValue(obj, MyEnum.Foo, null); //works
nullableEnumProperty.SetValue(obj, 1, null); // throws an exception !!!

完整说明here

答案 21 :(得分:8)

考虑这个奇怪的案例:

public interface MyInterface {
  void Method();
}
public class Base {
  public void Method() { }
}
public class Derived : Base, MyInterface { }

如果BaseDerived在同一个程序集中声明,编译器会使Base::Method虚拟并密封(在CIL中),即使Base没有实现界面。

如果BaseDerived在不同的程序集中,则在编译Derived程序集时,编译器不会更改其他程序集,因此它将在{{1这将是Derived的显式实现,它只会将调用委托给MyInterface::Method

编译器必须这样做才能支持关于接口的多态调度,即它必须使该方法成为虚拟。

答案 22 :(得分:8)

在我们使用的API中,返回域对象的方法可能会返回一个特殊的“null对象”。在执行此操作时,如果将Equals()true进行比较,则会覆盖比较运算符和null方法以返回return test != null ? test : GetDefault();

因此,此API的用户可能会使用以下代码:

if (test == null)
    return GetDefault();
return test;

或者可能更冗长,像这样:

GetDefault()

其中null是一个返回我们想要使用的默认值而不是return test ?? GetDefault(); 的方法。当我使用ReSharper并遵循它的建议将其中任何一个重写为以下内容时,这个惊喜让我感到惊讶:

null

如果测试对象是从API返回的空对象而不是正确的null,则代码的行为现在已更改,因为空合并运算符实际检查operator=,而不是正在运行Equals()或{{1}}。

答案 23 :(得分:7)

这个很难超越。当我尝试构建一个真正支持Begin / EndInvoke的RealProxy实现时,我遇到了它(感谢MS让没有可怕的黑客无法做到这一点)。此示例基本上是CLR中的错误,BeginInvoke的非托管代码路径不验证来自RealProxy.PrivateInvoke(以及我的Invoke覆盖)的返回消息是否返回IAsyncResult的实例。一旦它返回,CLR就会感到非常困惑,并且不知道最近会发生什么,正如底部测试所证明的那样。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Reflection;
using System.Runtime.Remoting.Messaging;

namespace BrokenProxy
{
    class NotAnIAsyncResult
    {
        public string SomeProperty { get; set; }
    }

    class BrokenProxy : RealProxy
    {
        private void HackFlags()
        {
            var flagsField = typeof(RealProxy).GetField("_flags", BindingFlags.NonPublic | BindingFlags.Instance);
            int val = (int)flagsField.GetValue(this);
            val |= 1; // 1 = RemotingProxy, check out System.Runtime.Remoting.Proxies.RealProxyFlags
            flagsField.SetValue(this, val);
        }

        public BrokenProxy(Type t)
            : base(t)
        {
            HackFlags();
        }

        public override IMessage Invoke(IMessage msg)
        {
            var naiar = new NotAnIAsyncResult();
            naiar.SomeProperty = "o noes";
            return new ReturnMessage(naiar, null, 0, null, (IMethodCallMessage)msg);
        }
    }

    interface IRandomInterface
    {
        int DoSomething();
    }

    class Program
    {
        static void Main(string[] args)
        {
            BrokenProxy bp = new BrokenProxy(typeof(IRandomInterface));
            var instance = (IRandomInterface)bp.GetTransparentProxy();
            Func<int> doSomethingDelegate = instance.DoSomething;
            IAsyncResult notAnIAsyncResult = doSomethingDelegate.BeginInvoke(null, null);

            var interfaces = notAnIAsyncResult.GetType().GetInterfaces();
            Console.WriteLine(!interfaces.Any() ? "No interfaces on notAnIAsyncResult" : "Interfaces");
            Console.WriteLine(notAnIAsyncResult is IAsyncResult); // Should be false, is it?!
            Console.WriteLine(((NotAnIAsyncResult)notAnIAsyncResult).SomeProperty);
            Console.WriteLine(((IAsyncResult)notAnIAsyncResult).IsCompleted); // No way this works.
        }
    }
}

输出:

No interfaces on notAnIAsyncResult
True
o noes

Unhandled Exception: System.EntryPointNotFoundException: Entry point was not found.
   at System.IAsyncResult.get_IsCompleted()
   at BrokenProxy.Program.Main(String[] args) 

答案 24 :(得分:7)

以下可能是我刚才缺乏的一般知识,但是呃。前段时间,我们有一个包含虚拟属性的bug案例。稍微抽象一下上下文,考虑以下代码,并将断点应用于指定区域:

class Program
{
    static void Main(string[] args)
    {
        Derived d = new Derived();
        d.Property = "AWESOME";
    }
}

class Base
{
    string _baseProp;
    public virtual string Property 
    { 
        get 
        {
            return "BASE_" + _baseProp;
        }
        set
        {
            _baseProp = value;
            //do work with the base property which might 
            //not be exposed to derived types
            //here
            Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
        }
    }
}

class Derived : Base
{
    string _prop;
    public override string Property 
    {
        get { return _prop; }
        set 
        { 
            _prop = value; 
            base.Property = value;
        } //<- put a breakpoint here then mouse over BaseProperty, 
          //   and then mouse over the base.Property call inside it.
    }

    public string BaseProperty { get { return base.Property; } private set { } }
}

Derived对象上下文中,将base.Property添加为手表或在快速计中键入base.Property时,您可以获得相同的行为。

花了一些时间才意识到发生了什么。最后,我受到了Quickwatch的启发。进入Quickwatch并浏览Derived对象d(或从对象的上下文this)并选择字段base时,Quickwatch顶部的编辑字段显示以下演员表:

((TestProject1.Base)(d))

这意味着如果base被替换为,那么调用将是

public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }

用于Watches,Quickwatch和调试鼠标悬停工具提示,因此在考虑多态性时,它显示"AWESOME"而不是"BASE_AWESOME"是有意义的。我仍然不确定为什么它会将其转换为演员表,一个假设是call可能无法从这些模块的上下文中获得,并且只有callvirt

无论如何,这显然不会改变任何功能,Derived.BaseProperty仍将真正返回"BASE_AWESOME",因此这不是我们工作中的bug的根源,只是一个令人困惑的组件。然而,我确实发现有趣的是它会误导开发人员在调试会话期间不会意识到这一事实,特别是如果Base未在您的项目中公开,而是被引用为第三方DLL,导致Devs只是说:

  

“Oi,等等......是什么?omg那个DLL是   喜欢,......做一些有趣的事情“

答案 25 :(得分:6)

你有没有想过C#编译器会生成无效的CIL?运行此项,您将获得TypeLoadException

interface I<T> {
  T M(T p);
}
abstract class A<T> : I<T> {
  public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
  public override T M(T p) { return p; }
  public int M(int p) { return p * 2; }
}
class C : B<int> { }

class Program {
  static void Main(string[] args) {
    Console.WriteLine(new C().M(42));
  }
}

我不知道它在C#4.0编译器中的表现如何。

编辑:这是我系统的输出:

C:\Temp>type Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

  interface I<T> {
    T M(T p);
  }
  abstract class A<T> : I<T> {
    public abstract T M(T p);
  }
  abstract class B<T> : A<T>, I<int> {
    public override T M(T p) { return p; }
    public int M(int p) { return p * 2; }
  }
  class C : B<int> { }

  class Program {
    static void Main(string[] args) {
      Console.WriteLine(new C().M(11));
    }
  }

}
C:\Temp>csc Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Temp>Program

Unhandled Exception: System.TypeLoadException: Could not load type 'ConsoleAppli
cation1.C' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyTo
ken=null'.
   at ConsoleApplication1.Program.Main(String[] args)

C:\Temp>peverify Program.exe

Microsoft (R) .NET Framework PE Verifier.  Version  3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

[token  0x02000005] Type load failed.
[IL]: Error: [C:\Temp\Program.exe : ConsoleApplication1.Program::Main][offset 0x
00000001] Unable to resolve token.
2 Error(s) Verifying Program.exe

C:\Temp>ver

Microsoft Windows XP [Version 5.1.2600]

答案 26 :(得分:6)

我不确定你是否说这是一个Windows Vista / 7奇怪或.Net奇怪但它让我挠了一下头。

string filename = @"c:\program files\my folder\test.txt";
System.IO.File.WriteAllText(filename, "Hello world.");
bool exists = System.IO.File.Exists(filename); // returns true;
string text = System.IO.File.ReadAllText(filename); // Returns "Hello world."

在Windows Vista / 7中,该文件实际上将写入C:\Users\<username>\Virtual Store\Program Files\my folder\test.txt

答案 27 :(得分:3)

关于C#,处理闭包的方式确实令人兴奋。

它没有将堆栈变量值复制到闭包自由变量,而是将预处理器魔术包装到一个对象中,然后将其从堆栈中移出 - 直接到堆中! :)

我想,这使得C#比ML本身(使用堆栈值复制AFAIK)更加功能完整(或lambda-complete huh))语言。 F#也有这个功能,就像C#一样。

这确实给我带来了很多乐趣,谢谢MS家伙们!

这不是一个奇怪或角落的情况......但是基于堆栈的VM语言确实出乎意料:)

答案 28 :(得分:3)

我不久前问过的一个问题:

Conditional operator cannot cast implicitly?

假设:

Bool aBoolValue;

其中aBoolValue分配为True或False;

以下内容无法编译:

Byte aByteValue = aBoolValue ? 1 : 0;

但这会:

Int anIntValue = aBoolValue ? 1 : 0;

提供的答案也很不错。

答案 29 :(得分:2)

c#中的范围确实很奇怪。让我举个例子:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

这无法编译,因为命令被重新声明?有一些有趣的猜测,为什么它在thread on stackoverflowmy blog中以这种方式运作。

答案 30 :(得分:2)

以下不起作用:

if (something)
    doit();
else
    var v = 1 + 2;

但这有效:

if (something)
    doit();
else {
    var v = 1 + 2;
}

答案 31 :(得分:2)

这里有一些我的:

  1. 当调用没有抛出NullReferenceException的实例方法时,这可以为null
  2. 不必为枚举
  3. 定义默认枚举值

    简单的第一个:      枚举NoZero             {                 数字= 1             }

            public bool ReturnsFalse()
            {
                //The default value is not defined!
                return Enum.IsDefined(typeof (NoZero), default(NoZero));
            }
    

    以下代码实际上可以打印出来!

     internal sealed class Strange
    {
        public void Foo()
        {
            Console.WriteLine(this == null);
        }
    }
    

    一个简单的客户端代码将导致这种情况发生    委托void HelloDelegate(Strange bar);

    public class Program
    {
        [STAThread()]
        public static void Main(string[] args)
        {
            Strange bar = null;
            var hello = new DynamicMethod("ThisIsNull",
                typeof(void), new[] { typeof(Strange) },
             typeof(Strange).Module);
            ILGenerator il = hello.GetILGenerator(256);
            il.Emit(OpCodes.Ldarg_0);
            var foo = typeof(Strange).GetMethod("Foo");
            il.Emit(OpCodes.Call, foo);
            il.Emit(OpCodes.Ret);
            var print = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate));
            print(bar);
            Console.ReadLine();
        }
    }
    

    在大多数语言中都是如此,只要被调用的实例方法不使用对象的状态。只有在访问对象的状态时才会取消引用

答案 32 :(得分:2)

这个非常简单但我仍然觉得它有点有趣。调用Foo后x的值是多少?

static int x = 0;

public static void Foo()
{
    try { return; }
    finally { x = 1; }
}

static void Main() { Foo(); }

答案 33 :(得分:1)

如果您有扩展方法:

public static bool? ToBoolean(this string s)
{
    bool result;

    if (bool.TryParse(s, out result))
        return result;
    else
        return null;
}

和这段代码:

string nullStr = null;
var res = nullStr.ToBoolean();

这不会引发异常,因为它是一个扩展方法(实际上是HelperClass.ToBoolean(null))而不是实例方法。这可能令人困惑。

答案 34 :(得分:-4)

这个让我真正感到困惑(我为长度道歉,但它是WinForm)。我曾经在newsgroups发布了它。

  

我遇到了一个有趣的错误。一世   有解决方法,但我想知道   问题的根源。我已经脱光了   它归结为一个短文并希望   有人可能会有一个想法   发生了什么事。

     

这是一个加载a的简单程序   控制到一个表格并绑定“Foo”   对抗组合框(“SelectedItem”)   因为它的“酒吧”属性和   datetimepicker(“Value”)就是这样的   “DateTime”属性。该   DateTimePicker.Visible值设置为   假。加载完毕后,选择   组合框然后尝试取消选择   它通过选中复选框。这是   组合框使其无法实现   保留焦点,你甚至不能   关闭表格,这是它的掌握   重点。

     

我找到了解决这个问题的三种方法   问题

     

a)删除对Bar的绑定(有点   很明显)

     

b)删除绑定到   日期时间

     

c)制作DateTimePicker   可见!?!

     

我目前正在运行Win2k。和.NET   2.00,我认为1.1有同样的问题。代码如下。

using System;
using System.Collections;
using System.Windows.Forms;

namespace WindowsApplication6
{
    public class Bar
    {
        public Bar()
        {
        }
    }

    public class Foo
    {
        private Bar m_Bar = new Bar();
        private DateTime m_DateTime = DateTime.Now;

        public Foo()
        {
        }

        public Bar Bar
        {
            get
            {
                return m_Bar;
            }
            set
            {
                m_Bar = value;
            }
        }

        public DateTime DateTime
        {
            get
            {
                return m_DateTime;
            }
            set
            {
                m_DateTime = value;
            }
        }
    }

    public class TestBugControl : UserControl
    {
        public TestBugControl()
        {
            InitializeComponent();
        }

        public void InitializeData(IList types)
        {
            this.cBoxType.DataSource = types;
        }

        public void BindFoo(Foo foo)
        {
            this.cBoxType.DataBindings.Add("SelectedItem", foo, "Bar");
            this.dtStart.DataBindings.Add("Value", foo, "DateTime");
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.checkBox1 = new System.Windows.Forms.CheckBox();
            this.cBoxType = new System.Windows.Forms.ComboBox();
            this.dtStart = new System.Windows.Forms.DateTimePicker();
            this.SuspendLayout();
            //
            // checkBox1
            //
            this.checkBox1.AutoSize = true;
            this.checkBox1.Location = new System.Drawing.Point(14, 5);
            this.checkBox1.Name = "checkBox1";
            this.checkBox1.Size = new System.Drawing.Size(97, 20);
            this.checkBox1.TabIndex = 0;
            this.checkBox1.Text = "checkBox1";
            this.checkBox1.UseVisualStyleBackColor = true;
            //
            // cBoxType
            //
            this.cBoxType.FormattingEnabled = true;
            this.cBoxType.Location = new System.Drawing.Point(117, 3);
            this.cBoxType.Name = "cBoxType";
            this.cBoxType.Size = new System.Drawing.Size(165, 24);
            this.cBoxType.TabIndex = 1;
            //
            // dtStart
            //
            this.dtStart.Location = new System.Drawing.Point(117, 40);
            this.dtStart.Name = "dtStart";
            this.dtStart.Size = new System.Drawing.Size(165, 23);
            this.dtStart.TabIndex = 2;
            this.dtStart.Visible = false;
            //
            // TestBugControl
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.dtStart);
            this.Controls.Add(this.cBoxType);
            this.Controls.Add(this.checkBox1);
            this.Font = new System.Drawing.Font("Verdana", 9.75F,
            System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
            ((byte)(0)));
            this.Margin = new System.Windows.Forms.Padding(4);
            this.Name = "TestBugControl";
            this.Size = new System.Drawing.Size(285, 66);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.CheckBox checkBox1;
        private System.Windows.Forms.ComboBox cBoxType;
        private System.Windows.Forms.DateTimePicker dtStart;
    }

    public class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += new EventHandler(Form1_Load);
        }

        void Form1_Load(object sender, EventArgs e)
        {
            InitializeControl();
        }

        public void InitializeControl()
        {
            TestBugControl control = new TestBugControl();
            IList list = new ArrayList();
            for (int i = 0; i < 10; i++)
            {
                list.Add(new Bar());
            }
            control.InitializeData(list);
            control.BindFoo(new Foo());
            this.Controls.Add(control);
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Text = "Form1";
        }

        #endregion
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

答案 35 :(得分:-4)

以下打印False而不是抛出溢出异常:

Console.WriteLine("{0}", yep(int.MaxValue ));


private bool yep( int val )
{
    return ( 0 < val * 2);
}

答案 36 :(得分:-18)

我认为这个问题的答案是因为.net使用字符串实习可能会导致相同的字符串指向同一个对象(因为字符串是可变的,这不是问题)

(我不是在讨论字符串类中重写的相等运算符)