我收集了一些极端案例和脑筋急转弯,总是想听到更多。这个页面只涵盖了c#语言的一些细节,但我也发现了。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上尝试过……)
只是为了澄清,这只是我正在寻找的事情的一个例子-我并不是特别寻找对这个奇怪现象的讨论/解释。(这和普通的弦乐实习不一样;特别地,当调用构造函数时,字符串实习通常不会发生。)我真的是在要求类似的奇怪行为。
还有其他的宝藏吗?
这个让我很困惑(我很抱歉篇幅太长,但它是WinForm)。我之前在新闻组里发的。
I've come across an interesting bug. I
have workarounds but i'd like to know
the root of the problem. I've stripped
it down into a short file and hope
someone might have an idea about
what's going on.
It's a simple program that loads a
control onto a form and binds "Foo"
against a combobox ("SelectedItem")
for it's "Bar" property and a
datetimepicker ("Value") for it's
"DateTime" property. The
DateTimePicker.Visible value is set to
false. Once it's loaded up, select the
combobox and then attempt to deselect
it by selecting the checkbox. This is
rendered impossible by the combobox
retaining the focus, you cannot even
close the form, such is it's grasp on
the focus.
I have found three ways of fixing this
problem.
a) Remove the binding to Bar (a bit
obvious)
b) Remove the binding to
DateTime
c) Make the DateTimePicker
visible !?!
I'm currently running Win2k. And .NET
2.00, I think 1.1 has the same problem. Code is below.
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());
}
}
}
如果作为Rec(0)调用(不在调试器下),该函数将做什么?
static void Rec(int i)
{
Console.WriteLine(i);
if (i < int.MaxValue)
{
Rec(i + 1);
}
}
答:
在32位JIT上,它应该导致StackOverflowException
在64位JIT上,它应该将所有数字打印为int。MaxValue
这是因为64位JIT编译器应用尾部调用优化,而32位JIT则没有。
不幸的是,我手头没有一台64位机器来验证这一点,但该方法确实满足尾部调用优化的所有条件。如果有人有的话,我很想看看这是不是真的。
This one's pretty hard to top. I ran into it while I was trying to build a RealProxy implementation that truly supports Begin/EndInvoke (thanks MS for making this impossible to do without horrible hacks). This example is basically a bug in the CLR, the unmanaged code path for BeginInvoke doesn't validate that the return message from RealProxy.PrivateInvoke (and my Invoke override) is returning an instance of an IAsyncResult. Once it's returned, the CLR gets incredibly confused and loses any idea of whats going on, as demonstrated by the tests at the bottom.
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)
我想我之前向您展示过这个,但我喜欢这里的乐趣——这需要一些调试才能跟踪!(原来的代码显然更加复杂和微妙……)
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是什么?
答:任何可空<T> -如int?。所有的方法都被重写,除了GetType()不能;因此它被强制转换为object(因此为null)来调用object. gettype()…哪个调用null;-p
更新:情节变得越来越复杂……Ayende Rahien在他的博客上提出了类似的挑战,但使用了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。现在去洗眼睛!
c#无障碍谜题
下面的派生类正在从它的基类中访问一个私有字段,编译器会默默地查看另一端:
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;
}
}
}
内部类可以完全访问外部类成员。在这种情况下,内部类也恰好派生自外部类。这允许我们“打破”私有成员的封装。