在C#或.NET中见过的最奇怪的angular落案例是什么?

我收集了几个angular落案例和脑筋急转弯 ,总是想听到更多。 该页面只包含C#语言的位和bob,但是我也发现了一些有趣的.NET内容。 例如,下面是一个不在页面上,但我觉得不可思议的:

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

我希望打印假 – 毕竟,“新”(带引用types) 总是创build一个新的对象,不是吗? C#和CLI的规范表明它应该。 那么,不是在这个特殊情况下。 它打印为True,并在我testing过的每个版本的框架上完成。 (我还没有尝试单声道,诚然…)

只是要清楚,这只是我所寻找的一个例子 – 我并不特别寻找这种古怪的讨论/解释。 (这和正常的string实际上不一样;特别是当调用构造函数时,string实际上通常不会发生。)我真的在要求类似的奇怪行为。

还有其他gem潜伏在那里?

我想我以前给你看过这个,但我喜欢这里的乐趣 – 这需要一些debugging来追踪! (原来的代码显然比较复杂和微妙…)

  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.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()调用被redirect到代理( MyFunnyProxyAttribute ),它返回null 。 现在去洗你的眼睛!

银行家舍入。

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

.Net框架采用称为银行家舍入的scheme或四舍五入。

在银行家的四舍五入中,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也是如此。

如果调用Rec(0) (不在debugging器下),这个函数会做什么?

 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位的机器来validation这一点,但是这个方法确实满足了所有的尾部优化的条件。 如果有人有我有兴趣,看看是否是真的。

分配这个!


这是我想在聚会上问的一个问题(这可能是为什么我不再被邀请):

你能编译下面的代码片段吗?

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

一个简单的作弊可能是:

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

但真正的解决scheme是这样的:

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

所以,值types(结构体)可以重新分配thisvariables是有点知道的事实。

几年前,在做忠诚计划的时候,我们在给客户的点数上有一个问题。 这个问题涉及到将double转换为int。

在下面的代码中:

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

i1 == i2

事实certificate,i1!= i2。 由于Convert和cast操作符中的舍入策略不同,实际值为:

 i1 == 14 i2 == 13 

最好调用Math.Ceiling()或Math.Floor()(或Math.Round,MidpointRounding满足我们的要求)

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

即使有枚举函数超载,它们也应该使0为整数。

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

testing例子:

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

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

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

它可以让你声明它,但是没有真正的用处,因为它总是要求你用另一只乌龟包装你在中心的任何类。

[笑话]我想这是乌龟一路下来… [/笑话]

这是我最近才发现的

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

上面看起来很疯狂,但实际上是合法的。不 ,真的(尽pipe我错过了一个关键部分,但它不像“添加一个名为IFoo的类”或“添加一个using别名到点IFoo上课“)。

看看能不能找出原因,那么: 谁说你不能实例化一个接口?

什么时候布尔既不是真也不是假?

比尔发现,你可以破解一个布尔值,所以如果A是真,B是真,(A和B)是假的。

黑客布尔人

我迟到了一点,但是我有三四五个:

  1. 如果你在一个没有被加载/显示的控件上轮询InvokeRequired,它会表示错误 – 如果你试图从另一个线程中改变它,就会炸毁你的面部( 解决scheme是引用this.Handle在创build者控制)。

  2. 另一个绊倒我的是给了一个会议:

     enum MyEnum { Red, Blue, } 

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

     enum MyEnum { Black, Red, Blue, } 

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

  3. 我有一个共享程序集中的一些方便的常量。我的前任已经留下了一些丑陋的只能得到的属性,我想我会摆脱混乱,只是使用公共常量。 当VS将它们编译为它们的值时,我感到有些惊讶,而不是引用。

  4. 如果您从另一个程序集实现了一个接口的新方法,但是重新引用了该程序集的旧版本,即使您已经实现了它(请参阅此处 ),也会得到TypeLoadException(不实现“NewMethod”)。

  5. Dictionary <,>:“项目返回的顺序是未定义的”。 这太可怕了 ,因为它有时可能会咬你,但是别人也可以,如果你只是盲目地认为Dictionary会玩得很好(“为什么不应该呢?我想,List就是这样”),你真的必须在你最终开始怀疑你的假设之前,先把它放在鼻子里。

VB.NET,可空和三元运算符:

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

这花了我一些时间来debugging,因为我希望i不包含Nothing

我真的包含什么? 0

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

我发现了第二个非常奇怪的angular落案例,远远超过了我的第一个。

String.Equals方法(string,string,StringComparison)实际上并没有副作用。

我正在研究一个代码块,这个代码块在某个函数的顶部有一行代码:

 stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase); 

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

代码竟然是安装一个处理程序,实际上是一个BeforeAssemblyLoad事件,并试图做

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

现在我不应该告诉你。 使用之前在string比较中没有使用过的文化会导致程序集加载。 InvariantCulture不是这个例外。

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

下面的unit testing演示了这个问题。

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

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

C#支持数组和列表之间的转换,只要数组不是多维的,并且types之间有inheritance关系,types是引用types

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

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

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

当一个或两个操作数是stringtypes时,二元+运算符执行string连接。 如果string连接的操作数为null ,则replace空string。 否则,通过调用从objecttypesinheritance的虚拟ToString方法,将任何非string操作数转换为其string表示forms。 如果ToString返回null ,则replace空string。

有趣的是 – 当我第一次看到它是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 ,这意味着这个操作码必须有特殊的行为来实现空string。

 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 

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

PropertyInfo.SetValue()可以将枚举赋予枚举,将int整型为可为null的枚举,将枚举枚举为可为空的枚举,但不能将整数赋给可为空的枚举。

 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 !!! 

这里完整的描述

如果你有一个通用的类,根据types的参数有可能是模糊的方法? 最近我碰到这种情况,写了一个双向字典。 我想写对称的Get()方法,它将返回任何parameter passing的相反部分。 像这样的东西:

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

如果你做一个T1T2是不同types的实例,一切都很好:

 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..." 

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

C#可访问性益智游戏


下面的派生类正在从它的基类访问一个私有字段 ,编译器默默地看着对方:

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

这个领域确实是私人的:

 private int m_basePrivateField = 0; 

谨慎猜测我们如何编译这样的代码?

回答


诀窍是声明DerivedBase的内部类:

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

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

Just found a nice little thing today:

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

This throws compile error.

The call to method 'Initialize' needs to be dynamically dispatched, but cannot be because it is part of a base access expression. Consider casting the dynamic arguments or eliminating the base access.

If I write base.Initialize(stuff as object); it works perfectly, however this seems to be a "magic word" here, since it does exactly the same, everything is still recieved as dynamic…

In an API we're using, methods that return a domain object might return a special "null object". In the implementation of this, the comparison operator and the Equals() method are overridden to return true if it is compared with null .

So a user of this API might have some code like this:

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

or perhaps a bit more verbose, like this:

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

where GetDefault() is a method returning some default value that we want to use instead of null . The surprise hit me when I was using ReSharper and following it's recommendation to rewrite either of this to the following:

 return test ?? GetDefault(); 

If the test object is a null object returned from the API instead of a proper null , the behavior of the code has now changed, as the null coalescing operator actually checks for null , not running operator= or Equals() .

Consider this weird case:

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

If Base and Derived are declared in the same assembly, the compiler will make Base::Method virtual and sealed (in the CIL), even though Base doesn't implement the interface.

If Base and Derived are in different assemblies, when compiling the Derived assembly, the compiler won't change the other assembly, so it will introduce a member in Derived that will be an explicit implementation for MyInterface::Method that will just delegate the call to Base::Method .

The compiler has to do this in order to support polymorphic dispatch with regards to the interface, ie it has to make that method virtual.

The following might be general knowledge I was just simply lacking, but eh. Some time ago, we had a bug case which included virtual properties. Abstracting the context a bit, consider the following code, and apply breakpoint to specified area :

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

While in the Derived object context, you can get the same behavior when adding base.Property as a watch, or typing base.Property into the quickwatch.

Took me some time to realize what was going on. In the end I was enlightened by the Quickwatch. When going into the Quickwatch and exploring the Derived object d (or from the object's context, this ) and selecting the field base , the edit field on top of the Quickwatch displays the following cast:

 ((TestProject1.Base)(d)) 

Which means that if base is replaced as such, the call would be

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

for the Watches, Quickwatch and the debugging mouse-over tooltips, and it would then make sense for it to display "AWESOME" instead of "BASE_AWESOME" when considering polymorphism. I'm still unsure why it would transform it into a cast, one hypothesis is that call might not be available from those modules' context, and only callvirt .

Anyhow, that obviously doesn't alter anything in terms of functionality, Derived.BaseProperty will still really return "BASE_AWESOME" , and thus this was not the root of our bug at work, simply a confusing component. I did however find it interesting how it could mislead developpers which would be unaware of that fact during their debug sessions, specially if Base is not exposed in your project but rather referenced as a 3rd party DLL, resulting in Devs just saying :

"Oi, wait..what ? omg that DLL is like, ..doing something funny"

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) 

I'm not sure if you'd say this is a Windows Vista/7 oddity or a .Net oddity but it had me scratching my head for a while.

 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." 

In Windows Vista/7 the file will actually be written to C:\Users\<username>\Virtual Store\Program Files\my folder\test.txt

Have you ever thought the C# compiler could generate invalid CIL? Run this and you'll get a TypeLoadException :

 interface I<T> { TM(T p); } abstract class A<T> : I<T> { public abstract TM(T p); } abstract class B<T> : A<T>, I<int> { public override TM(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)); } } 

I don't know how it fares in the C# 4.0 compiler though.

EDIT : this is the output from my system:

 C:\Temp>type Program.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { interface I<T> { TM(T p); } abstract class A<T> : I<T> { public abstract TM(T p); } abstract class B<T> : A<T>, I<int> { public override TM(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] 

There is something really exciting about C#, the way it handles closures.

Instead of copying the stack variable values to the closure free variable, it does that preprocessor magic wrapping all occurences of the variable into an object and thus moves it out of stack – straight to the heap! 🙂

I guess, that makes C# even more functionally-complete (or lambda-complete huh)) language than ML itself (which uses stack value copying AFAIK). F# has that feature too, as C# does.

That does bring much delight to me, thank you MS guys!

It's not an oddity or corner case though… but something really unexpected from a stack-based VM language 🙂

From a question I asked not long ago:

条件运算符不能隐式转换?

鉴于:

 Bool aBoolValue; 

Where aBoolValue is assigned either True or False;

The following will not compile:

 Byte aByteValue = aBoolValue ? 1 : 0; 

But this would:

 Int anIntValue = aBoolValue ? 1 : 0; 

The answer provided is pretty good too.

The scoping in c# is truly bizarre at times. Lets me give you one example:

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

This fails to compile, because command is redeclared? There are some interested guesswork as to why it works that way in this thread on stackoverflow and in my blog .