首页 文章

_138097在C#或.NET中看到了什么? [关闭]

提问于
浏览
322

我收集了一些角落案件和brain teasers并且总是希望听到更多 . 该页面仅涵盖C#语言位和bobs,但我也发现核心.NET的东西也很有趣 . 例如,这里是页面上的's one which isn' t,但我发现它令人难以置信:

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

我希望打印False - 毕竟,"new"(带引用类型)总是会创建一个新对象,并且不会对它进行测试 . (我没有在Mono上尝试过,诚然......)

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

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

30 回答

  • 8

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

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

    上面看起来很疯狂乍一看,但是 actually legal . 没有,真的(虽然我错过了一个关键部分,但是 isn't 任何hacky都像“添加一个名为 IFoo " or "的类,在一个类中添加 using alias指向 IFoo ” ) .

    看看你能弄清楚原因,然后:Who says you can’t instantiate an interface?

  • 10

    我不确定你是否说这是一个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

  • 6

    银行家的四舍五入 .

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

    .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也是如此 .

  • 15

    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[]'
    
  • 7

    考虑这个奇怪的情况:

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

    如果 BaseDerived 在同一个程序集中声明,则编译器将使 Base::Method 虚拟并密封(在CIL中),即使 Base 未实现该接口 .

    如果 BaseDerived 在不同的程序集中,则在编译 Derived 程序集时,编译器不会更改其他程序集,因此它将在 Derived 中引入一个成员,该成员将是 MyInterface::Method 的显式实现,它将委托将调用委托给 Base::Method .

    编译器必须这样做以便支持关于接口的多态分派,即它必须使该方法是虚拟的 .

  • 3

    这个很难达到顶峰 . 当我试图 Build 一个真正支持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)
    
  • 3

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

    在下面的代码中:

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

    does i1 == i2

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

    i1 == 14
    i2 == 13
    

    调用Math.Ceiling()或Math.Floor()(或MidgleRounding符合我们要求的Math.Round)总是更好

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

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

    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?");
    }
    

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

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

    有了这个, new() 调用被重定向到代理( MyFunnyProxyAttribute ),它返回 null . 现在去洗眼睛吧!

  • 10

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

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

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

  • 8

    即使存在枚举函数重载,它们也应该使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");
            }
        }
    }
    
  • 10

    以下可能是我只是缺乏的一般知识,但是呃 . 前段时间,我们有一个包含虚拟属性的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 添加为 Watch 或在快速 Watch 中键入 base.Property 时,可以获得相同的行为 .

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

    ((TestProject1.Base)(d))
    

    这意味着如果基地被替换,那么呼叫将是

    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就像是,...做一些有趣的事情”

  • 47

    C#有一些令人兴奋的事情,它处理闭包的方式 .

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

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

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

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

  • 2

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

    String.Equals方法(String,String,StringComparison)实际上不是副作用 .

    我正在研究一个代码块,它在一些函数的顶部单独使用它:

    stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);
    

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

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

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

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

  • 56

    When is a Boolean neither True nor False?

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

    Hacked Booleans

  • 74

    刚刚发现一件好事:

    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(东西作为对象);它完美地工作,但这似乎是一个“神奇的词”,因为它完全相同,一切仍然被收到动态......

  • 67

    有意思 - 当我第一次看到它时,我认为它是C#编译器正在检查的东西,但即使你直接发出IL以消除任何干扰的机会它仍然会发生,这意味着它真的是 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);
    

    如果您检查 string.Empty ,它也等同于 true ,这意味着此操作码必须对实习空字符串具有特殊行为 .

  • 176

    C#辅助功能Puzzler


    以下派生类从其基类访问 private field ,编译器静默查找另一端:

    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;
            }
        }
    }
    

    内部类可以完全访问外部类成员 . 在这种情况下,内部类也恰好来自外部类 . 这允许我们“打破”私人成员的封装 .

  • 12

    你有没有想过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编译器中的表现如何 .

    EDIT :这是我系统的输出:

    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]
    
  • 28

    如果调用 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位机器来验证这一点,但该方法确实满足了尾部调用优化的所有条件 . 如果有人有,我有兴趣看看它是否属实 .

  • 18

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

    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的错误:

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

  • 216

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

    以下单元测试演示了该问题 .

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

    [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);
            }
        }
    
  • 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..."
    

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

  • 7

    在我们使用的API中,返回域对象的方法可能会返回特殊的"null object" . 在执行此操作时,如果将 Equals()null 进行比较,则会重写比较运算符和 Equals() 方法以返回 true .

    所以这个API的用户可能有这样的代码:

    return test != null ? test : GetDefault();
    

    或许更冗长,像这样:

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

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

    return test ?? GetDefault();
    

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

  • 10

    分配这个!


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

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

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

    一个简单的欺骗可能是:

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

    但真正的解决方案是:

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

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

  • 394

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

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

    它允许你声明它但没有实际用途,因为它总是会要求你用另一只Turtle包装你在中心的任何类 .

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

  • 65

    我'm arriving a bit late to the party, but I'得到三四五:

    • 如果你在一个尚未加载/显示的控件上轮询InvokeRequired,它会说是假的 - 如果你试图从另一个线程改变它,那就在你的脸上爆炸(the solution是引用这个 . 在创建者中的手柄控制) .

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

    enum MyEnum
    {
        Red,
        Blue,
    }
    

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

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

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

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

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

    • Dictionary <,>:"The order in which the items are returned is undefined" . 这太可怕了,因为它有时候可能会咬你,但是会工作其他人,如果你只是盲目地认为词典会发挥得很好("why shouldn't it? I thought, List does"),那么在你最终开始质疑之前,你真的必须掏鼻子 . 假设 .

  • 20
    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
    

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

  • 100

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

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

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

    我真的包含什么? 0 .

    这是令人惊讶的但实际上_118151_行为:VB.NET中的 Nothing 与CLR中的 null 不完全相同: Nothing 对于值类型 T 可能意味着 nulldefault(T) ,具体取决于上下文 . 在上面的例子中, If 推断 IntegerNothing5 的公共类型,因此,在这种情况下, Nothing 表示 0 .

  • 112

    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

  • 33

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

    Conditional operator cannot cast implicitly?

    鉴于:

    Bool aBoolValue;
    

    aBoolValue 被指定为True或False;

    以下内容无法编译:

    Byte aByteValue = aBoolValue ? 1 : 0;
    

    但这会:

    Int anIntValue = aBoolValue ? 1 : 0;
    

    提供的答案也很不错 .

相关问题