C#的隐藏功能?

时间:2008-08-12 16:32:25

标签: c# hidden-features

在我从this question了解到以下内容后,我想到了这一点:

where T : struct

我们C#开发人员都知道C#的基础知识。我的意思是声明,条件,循环,运算符等。

我们中的一些人甚至掌握了Genericsanonymous typeslambdasLINQ等内容......

但即使是C#粉丝,瘾君子,专家也几乎不知道C#最隐藏的功能或技巧是什么?

到目前为止,这是显示的功能:


关键字

属性

语法

语言功能

Visual Studio功能

框架

方法和属性

提示&花样

  • Andreas H.R. Nilsson
  • 的事件处理程序的好方法
  • John
  • 进行大写比较
  • 通过dp
  • 访问没有反映的匿名类型
  • 通过Will
  • 延迟实例化集合属性的快捷方法
  • roosteronacid
  • 的类似JavaScript的匿名内联函数

其他

296 个答案:

答案 0 :(得分:752)

这本身不是C#,但我没有看到任何真正使用System.IO.Path.Combine()的人。事实上,整个Path类非常有用,但是没有人使用它!

我愿意打赌每个制作应用程序都有以下代码,即使它不应该:

string path = dir + "\\" + fileName;

答案 1 :(得分:585)

lambdas和类型推断被低估了。 Lambdas可以有多个语句,并且自动加倍作为兼容的委托对象(只需确保签名匹配),如下所示:

Console.CancelKeyPress +=
    (sender, e) => {
        Console.WriteLine("CTRL+C detected!\n");
        e.Cancel = true;
    };

请注意,我没有new CancellationEventHandler,我也不必指定sendere的类型,它们可以从事件中推断出来。这就是为什么编写整个delegate (blah blah)不那么麻烦,这也要求你指定参数类型。

Lambdas不需要返回任何内容,类型推断在这样的上下文中非常强大。

顺便说一句,你总是可以在功能编程意义上返回使Lambdas 的Lambdas。例如,这是一个lambda,它使lambda处理Button.Click事件:

Func<int, int, EventHandler> makeHandler =
    (dx, dy) => (sender, e) => {
        var btn = (Button) sender;
        btn.Top += dy;
        btn.Left += dx;
    };

btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);

请注意链接:(dx, dy) => (sender, e) =>

这就是为什么我很高兴参加函数式编程课程: - )

除了C中的指针,我认为这是你应该学习的另一个基本要素: - )

答案 2 :(得分:528)

来自Rick Strahl

你可以连锁?运算符,以便您可以进行一堆空比较。

string result = value1 ?? value2 ?? value3 ?? String.Empty;

答案 3 :(得分:455)

别名仿制药:

using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;

它允许您使用ASimpleName,而不是Dictionary<string, Dictionary<string, List<string>>>

在很多地方使用相同的通用大而复杂的东西时使用它。

答案 4 :(得分:438)

  

来自CLR via C#

     

当规范化字符串时,它是高度的   建议您使用   ToUpperInvariant而不是   ToLowerInvariant因为微软有   优化了执行代码   大写比较

我记得有一次我的同事在比较之前总是将字符串换成大写字母。我一直想知道为什么他这样做,因为我觉得首先转换为小写更为“自然”。现在读完这本书后,我知道为什么。

答案 5 :(得分:409)

我最喜欢的技巧是使用null coalesce operator和括号为我自动实例化集合。

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }

答案 6 :(得分:314)

避免检查空事件处理程序

在声明时向事件添加一个空委托,禁止在调用它之前始终检查该事件是否真棒。例如:

public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!

让你这样做

public void DoSomething()
{
    Click(this, "foo");
}

而不是这个

public void DoSomething()
{
    // Unnecessary!
    MyClickHandler click = Click;
    if (click != null) // Unnecessary! 
    {
        click(this, "foo");
    }
}

另请参阅Eric Lippert关于此主题的related discussion和此blog post(以及可能存在的缺点)。

答案 7 :(得分:305)

其他所有,加上

1)隐式泛型(为什么只对方法而不是对类?)

void GenericMethod<T>( T input ) { ... }

//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23);      //Is enough.

2)带有一个参数的简单lambda:

x => x.ToString() //simplify so many calls

3)匿名类型和初始化:

//Duck-typed: works with any .Add method.
var colours = new Dictionary<string, string> {
    { "red", "#ff0000" },
    { "green", "#00ff00" },
    { "blue", "#0000ff" }
};

int[] arrayOfInt = { 1, 2, 3, 4, 5 };

另一个:

4)自动属性可以有不同的范围:

public int MyId { get; private set; }

感谢@pzycoman提醒我:

5)命名空间别名(不是你可能需要这种特殊区别):

using web = System.Web.UI.WebControls;
using win = System.Windows.Forms;

web::Control aWebControl = new web::Control();
win::Control aFormControl = new win::Control();

答案 8 :(得分:286)

很长一段时间我都不知道“as”关键字。

MyClass myObject = (MyClass) obj;

VS

MyClass myObject = obj as MyClass;

如果obj不是MyClass,则第二个将返回null,而不是抛出一个类转换异常。

答案 9 :(得分:262)

我喜欢的两件事是自动属性,因此您可以进一步折叠代码:

private string _name;
public string Name
{
    get
    {
        return _name;
    }
    set
    {
        _name = value;
    }
}

变为

public string Name { get; set;}

也是对象初始化器:

Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();

变为

Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}

答案 10 :(得分:255)

泛型类型中的'default'关键字:

T t = default(T);
如果T是引用类型,则

导致'null',如果是int,则返回0,如果是布尔值则返回false, 等等。

答案 11 :(得分:226)

一般属性,但最重要的是DebuggerDisplay。为您节省数年。

答案 12 :(得分:221)

  

@告诉编译器忽略any   转义字符串中的字符。

只是想澄清一下......它并没有告诉它忽略转义字符,它实际上告诉编译器将字符串解释为文字。

如果你有

string s = @"cat
             dog
             fish"

它实际上会打印出来(注意它甚至包括用于缩进的空格):

cat
             dog
             fish

答案 13 :(得分:220)

我认为当与Generics和Lambdas结合使用时,C#(。NET 3.5)最不受欢迎和鲜为人知的功能之一是Expression Trees,尤其是。这是一种API创建方法,像NInject和Moq这样的新库正在使用。

例如,假设我想要使用API​​注册方法,并且API需要获取方法名称

鉴于此课程:

public class MyClass
{
     public void SomeMethod() { /* Do Something */ }
}

以前,看到开发人员使用字符串和类型(或其他主要基于字符串的东西)这样做是很常见的:

RegisterMethod(typeof(MyClass), "SomeMethod");

嗯,由于缺乏强力打字,这很糟糕。如果我重命名“SomeMethod”怎么办?现在,在3.5中,我可以以强类型的方式做到这一点:

RegisterMethod<MyClass>(cl => cl.SomeMethod());

RegisterMethod类使用Expression<Action<T>>这样:

void RegisterMethod<T>(Expression<Action<T>> action) where T : class
{
    var expression = (action.Body as MethodCallExpression);

    if (expression != null)
    {
        // TODO: Register method
        Console.WriteLine(expression.Method.Name);
    }
}

这是我现在爱上Lambdas和Expression Trees的一个重要原因。

答案 14 :(得分:209)

yield”会浮现在我脑海中。像[DefaultValue()]这样的一些属性也是我的最爱。

var”关键字更为人所知,但您也可以在.NET 2.0应用程序中使用它(只要您use the .NET 3.5 compiler并将其设置为输出2.0代码)似乎并不是很清楚。

编辑:kokos,谢谢你指出了??运算符,这确实非常有用。由于它有点难以谷歌(因为??只是被忽略),这里是该运营商的MSDN文档页面: ?? Operator (C# Reference)

答案 15 :(得分:198)

我倾向于发现大多数C#开发人员都不知道'可空'类型。基本上,可以具有空值的基元。

double? num1 = null; 
double num2 = num1 ?? -100;

将可为空的双重 num1 设置为null,然后将常规double, num2 设置为 num1 -100 如果 num1 为空。

http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx

关于Nullable类型的另一件事:

DateTime? tmp = new DateTime();
tmp = null;
return tmp.ToString();

返回String.Empty。查看this链接了解详情

答案 16 :(得分:193)

以下是一些有趣的隐藏C#功能,以未记录的C#关键字的形式出现:

__makeref

__reftype

__refvalue

__arglist

这些是未记录的C#关键字(甚至Visual Studio识别它们!),这些关键字是为了在泛型之前更有效的装箱/拆箱而添加的。它们与System.TypedReference结构协同工作。

还有__arglist,用于可变长度参数列表。

有些人不太了解是System.WeakReference - 一个非常有用的类,它跟踪一个对象,但仍允许垃圾收集器收集它。

最有用的“隐藏”功能是yield return关键字。它并没有真正隐藏,但很多人都不知道。 LINQ建立于此之上;它允许通过在引擎盖下生成状态机来执行延迟执行的查询。 Raymond Chen最近发布了internal, gritty details

答案 17 :(得分:185)

Unions(C ++共享内存类型)纯粹,安全的C#

不依赖于不安全模式和指针,您可以让类成员在类/结构中共享内存空间。鉴于以下课程:

[StructLayout(LayoutKind.Explicit)]
public class A
{
    [FieldOffset(0)]
    public byte One;

    [FieldOffset(1)]
    public byte Two;

    [FieldOffset(2)]
    public byte Three;

    [FieldOffset(3)]
    public byte Four;

    [FieldOffset(0)]
    public int Int32;
}

您可以通过操作Int32字段来修改字节字段的值,反之亦然。例如,这个程序:

    static void Main(string[] args)
    {
        A a = new A { Int32 = int.MaxValue };

        Console.WriteLine(a.Int32);
        Console.WriteLine("{0:X} {1:X} {2:X} {3:X}", a.One, a.Two, a.Three, a.Four);

        a.Four = 0;
        a.Three = 0;
        Console.WriteLine(a.Int32);
    }

输出:

2147483647
FF FF FF 7F
65535

添加 使用System.Runtime.InteropServices;

答案 18 :(得分:176)

使用@作为关键字的变量名。

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 

答案 19 :(得分:168)

如果您想在不调用任何finally块或终结器的情况下退出程序,请使用FailFast

Environment.FailFast()

答案 20 :(得分:153)

从方法中返回匿名类型并在不反射的情况下访问成员。

// Useful? probably not.
private void foo()
{
    var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
    Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}

object GetUserTuple()
{
    return new { Name = "dp", Badges = 5 };
}    

// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
   return (T) obj;
}

答案 21 :(得分:146)

这是一个有用的正则表达式和文件路径:

"c:\\program files\\oldway"
@"c:\program file\newway"

@告诉编译器忽略字符串中的任何转义字符。

答案 22 :(得分:142)

混入。基本上,如果要向多个类添加一个功能,但不能为所有类使用一个基类,请让每个类实现一个接口(没有成员)。然后,为接口编写扩展方法,即

public static DeepCopy(this IPrototype p) { ... }

当然,牺牲一些清晰度。但它有效!

答案 23 :(得分:131)

  

不确定为什么有人会想要使用Nullable&lt; bool&gt;虽然。 : - )

是的,是的,FileNotFound

答案 24 :(得分:117)

这个不是“隐藏”的,因为它被错误命名。

很多人都关注算法“map”,“reduce”和“filter”。大多数人没有意识到的是.NET 3.5添加了所有这三种算法,但基于它们是LINQ的一部分,它给了它们非常的SQL-ish名称。

  

“map”=&gt;选择
转换数据   从一种形式到另一种形式

     

“reduce”=&gt;聚合
聚合   将值转换为单个结果

     

“filter”=&gt;其中
过滤数据   基于标准

使用LINQ对过去采用迭代和条件的集合进行内联工作的能力非常有价值。值得了解所有LINQ扩展方法如何帮助您的代码更加紧凑和可维护。

答案 25 :(得分:115)

Environment.NewLine

用于系统无关的换行符。

答案 26 :(得分:111)

如果您尝试在String.Format表达式中使用大括号...

int foo = 3;
string bar = "blind mice";
String.Format("{{I am in brackets!}} {0} {1}", foo, bar);
//Outputs "{I am in brackets!} 3 blind mice"

答案 27 :(得分:104)

  1. ?? - 合并运算符
  2. 使用(statement / directive) - 非常好的关键字,不仅可以用来调用Dispose
  3. readonly - 应该更多地使用
  4. netmodules - 太糟糕了,Visual Studio中没有支持

答案 28 :(得分:103)

@Ed,我对发布这个有点保持沉默,因为它只不过是挑剔。但是,我会在您的代码示例中指出:

MyClass c;
  if (obj is MyClass)
    c = obj as MyClass

如果您要使用'is',为什么要使用'as'进行安全演员?如果你已经确定obj确实是MyClass,那就是沼泽标准演员:

c = (MyClass)obj

......永远不会失败。

同样,你可以说:

MyClass c = obj as MyClass;
if(c != null)
{
   ...
}

我不太了解.NET的内部信息,但我的直觉告诉我,这会最多将两个类型转换操作减少到最多一个。无论如何,它几乎不可能破坏处理银行;就个人而言,我认为后一种形式看起来也更清晰。

答案 29 :(得分:98)

也许不是一种先进的技术,但我总是看到让我疯狂的一种技术:

if (x == 1)
{
   x = 2;
}
else
{
   x = 3;
}

可以浓缩为:

x = (x==1) ? 2 : 3;

答案 30 :(得分:94)

许多人没有意识到他们可以使用OrdinalIgnoreCase来比较字符串,而不必使用someString.ToUpper()。这将消除额外的字符串分配开销。

if( myString.ToUpper() == theirString.ToUpper() ){ ... }

变为

if( myString.Equals( theirString, StringComparison.OrdinalIgnoreCase ) ){ ... }

答案 31 :(得分:80)

刚刚了解到,匿名类型可以从变量名称推断属性名称:

string hello = "world";
var o = new { hello };
Console.WriteLine(o.hello);

答案 32 :(得分:75)

老实说,根据定义的专家应该知道这些东西。但要回答您的问题: Built-In Types Table (C# Reference)

标记数字的编译器众所周知:

Decimal = M
Float = F
Double = D

// for example
double d = 30D;

然而,这些更加模糊:

Long = L
Unsigned Long = UL
Unsigned Int = U

答案 33 :(得分:75)

我喜欢在列表中查找内容: -

bool basketContainsFruit(string fruit) {
  return new[] { "apple", "orange", "banana", "pear" }.Contains(fruit);
}

而不是: -

bool basketContainsFruit(string fruit) {
  return fruit == "apple" || fruit == "orange" || fruit == "banana" ||
    fruit == "pear";
}

在实践中没有那么多,但是将项目与搜索主题相匹配的想法可能非常有用+简洁。

答案 34 :(得分:73)

InternalsVisibleTo 属性是一个众所周知的属性,但在某些情况下可以更加方便。它基本上允许另一个程序集能够访问定义程序集的“内部”元素。

答案 35 :(得分:72)

这是C#4.0中字符串类的新方法:

String.IsNullOrWhiteSpace(String value)

现在是时候了。

答案 36 :(得分:70)

我在使用ReSharper时选择了这个:

隐式方法组转换

//If given this:
var myStrings = new List<string>(){"abc","def","xyz"};
//Then this:
myStrings.ForEach(s => Console.WriteLine(s));
//Is equivalent to this:
myStrings.ForEach(Console.WriteLine);

有关详情,请参阅“Implicit Method Group Conversion in C#”。

答案 37 :(得分:69)

调试时,您可以在Watch \ QuickWatch \ Immediate窗口中键入$exception,并获取有关当前帧异常的所有信息。如果你有第一次机会异常开启,这非常有用!

答案 38 :(得分:68)

  • System.STransactions中的TransactionScope和DependentTransaction是一种在.NET中使用事务处理的轻量级方法 - 它不仅适用于Database transactions either
  • String.IsNullOrEmpty让我很惊讶,很多开发人员都不知道
  • List.ForEach - 使用委托方法
  • 遍历您的通用列表

还有更多,但这是我头脑中最明显的三个......

答案 39 :(得分:67)

Dictionary.TryGetValue(K键,输出V值)

作为一个支票和一个进入。而不是;

if(dictionary.ContainsKey(key)) 
{
    value = dictionary[key];
    ...
}

你可以做;

if(dictionary.TryGetValue(key, out value)) 
{ ... }

并且已设置该值。

答案 40 :(得分:66)

Conditional string.Format

根据数字是正数,负数还是零来对数字应用不同的格式。

string s = string.Format("{0:positive;negative;zero}", i);

e.g。

string format = "000;-#;(0)";

string pos = 1.ToString(format);     // 001
string neg = (-1).ToString(format);  // -1
string zer = 0.ToString(format);     // (0)

答案 41 :(得分:64)

事件本身就是代理,任何委托对象都可以附加多个函数,并分别使用+ =和 - =运算符从中分离出来。

事件也可以使用add / remove控制,类似于get / set,除非在使用+ =和 - =时调用它们:

public event EventHandler SelectiveEvent(object sender, EventArgs args) 
  { add 
     { if (value.Target == null) throw new Exception("No static handlers!");
       _SelectiveEvent += value;
     }
    remove
     { _SelectiveEvent -= value;
     }
  } EventHandler _SelectiveEvent;

答案 42 :(得分:61)

不要忘记 goto

答案 43 :(得分:57)

更多的运行时功能,但我最近了解到有两个垃圾收集器。工作站gc和服务器gc。 Workstation是客户端版本的Windows的默认设置,但服务器在多核计算机上要快得多。


<configuration>
   <runtime>
      <gcServer enabled="true"/>
   </runtime>
</configuration>

小心点。服务器gc需要更多内存。

答案 44 :(得分:55)

使用“throw;”而不是“抛出前”;保留堆栈跟踪

如果在不添加其他信息的情况下重新抛出异常,请使用“throw”而不是“throw ex”。 catch块中的空“throw”语句将发出特定的IL,它会在保留原始堆栈跟踪的同时重新抛出异常。 “throw ex”将堆栈跟踪丢失到异常的原始源。

答案 45 :(得分:55)

其他未充分利用的运营商是checkedunchecked

short x = 32767;   // 32767 is the max value for short
short y = 32767;
int z1 =  checked((short)(x + y));   //will throw an OverflowException
int z2 =  unchecked((short)(x + y)); // will return -2
int z3 =  (short)(x + y);            // will return -2

答案 46 :(得分:55)

我看不到上面这个 - 我直到最近才意识到你可以做的一个是从另一个调用一个构造函数:

class Example
{
    public Example(int value1)
        : this(value1, "Default Value")
    {
    }

    public Example(int value1, string value2)
    {
        m_Value1 = value1;
        m_value2 = value2;
    }

    int m_Value1;
    string m_value2;
}

答案 47 :(得分:48)

我只是想在没有评论的情况下复制该代码。因此,诀窍是只需按Alt键,然后突出显示您喜欢的矩形。(例如下面)。

protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        //if (e.CommandName == "sel")
        //{
        //    lblCat.Text = e.CommandArgument.ToString();
        //}
    }

在上面的代码中,如果我想选择:

e.CommandName == "sel"

lblCat.Text = e.Comman

然后我按下ALt键并选择矩形,无需取消注释行。

检查一下。

答案 48 :(得分:48)

我遇到的一些隐藏功能:

  • stackalloc允许您在堆栈上分配数组
  • 没有显式参数列表的匿名方法,可以隐式转换为任何具有非out / ref参数的委托类型(非常方便事件,如前面的评论中所述)
  • 很多人都不知道究竟是什么事件(添加/删除一对方法,比如属性的get / set); C#中的字段式事件确实声明了变量事件
  • 可以重载==!=运算符以返回bool以外的类型。奇怪但真实。
  • C#3中的查询表达式翻译在某些方面非常“简单” - 这意味着你可以让它做一些very odd things
  • 可空类型具有特殊的装箱行为:空值被装箱为空引用,您也可以从null取消装入可空类型。

答案 49 :(得分:47)

达科他的@David:

Console.WriteLine( "-".PadRight( 21, '-' ) );

我曾经这样做,直到我发现String类有一个构造函数,允许你以更干净的方式做同样的事情:

new String('-',22);

答案 50 :(得分:46)

volatile关键字告诉编译器可以同时修改多个线程的字段。

答案 51 :(得分:45)

params关键字,即

public void DoSomething(params string[] theStrings)
{
  foreach(string s in theStrings)
  {
    // Something with the Strings…
  }
}

被称为

DoSomething(“The”, “cat”, “sat”, “on”, “the” ,”mat”);

答案 52 :(得分:45)

我喜欢的几件事:

- 如果您创建类似于

的界面
 public interface SomeObject<T> where T : SomeObject<T>, new()

你强制从这个接口继承的任何东西 包含无参数构造函数。它非常有用 我碰过的几件事。

- 使用匿名类型动态创建有用的对象:

var myAwesomeObject = new {Name="Foo", Size=10};

- 最后,许多Java开发人员都熟悉如下语法:

public synchronized void MySynchronizedMethod(){}

但是,在C#中,这不是有效的语法。解决方法是方法属性:

 [MethodImpl(MethodImplOptions.Synchronized)]
 public void MySynchronizedMethod(){}

答案 53 :(得分:44)

Foreach使用Duck Typing

Krzysztof Cwalinas blog上对此进行释义或无耻地窃取。比任何事都更有趣的琐事。

为了让您的对象支持foreach,您必须实现 IEnumerable 。即这不是约束,编译器不会检查它。检查的是

  • 您的对象提供了一个公共方法 GetEnumerator
    • 不参数
    • 返回包含两个成员的类型
      1. 无参数方法MoveNext 返回布尔值
      2. 属性当前,其中包含返回对象的getter

例如,

class Foo
{
    public Bar GetEnumerator() { return new Bar(); }

    public struct Bar
    {
        public bool MoveNext()
        {
            return false;
        }

        public object Current
        {
            get { return null; }
        }
    }
}

// the following complies just fine:
Foo f = new Foo();
foreach (object o in f)
{
    Console.WriteLine("Krzysztof Cwalina's da man!");
}

答案 54 :(得分:42)

静态构造函数。

实例:

public class Example
{
    static Example()
    {
        // Code to execute during type initialization
    }

    public Example()
    {
        // Code to execute during object initialization
    }
}

静态类:

public static class Example
{
    static Example()
    {
        // Code to execute during type initialization
    }
}

MSDN says

  

静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前会自动调用它。

例如:

public class MyWebService
{
    public static DateTime StartTime;

    static MyWebService()
    {
        MyWebService.StartTime = DateTime.Now;
    }

    public TimeSpan Uptime
    {
        get { return DateTime.Now - MyWebService.StartTime; }
    }
}

但是,您也可以轻松完成:

public class MyWebService
{
    public static DateTime StartTime = DateTime.Now;

    public TimeSpan Uptime
    {
        get { return DateTime.Now - MyWebService.StartTime; }
    }
}

因此,当您确实需要使用静态构造函数时,您将很难找到任何实例。

MSDN提供了有关静态构造函数的有用说明:

  
      
  • 静态构造函数不接受访问修饰符或具有参数。

  •   
  • 自动调用静态构造函数来初始化类   在创建第一个实例之前   或引用任何静态成员。

  •   
  • 无法直接调用静态构造函数。

  •   
  • 用户无法控制何时执行静态构造函数   程序

  •   
  • 静态构造函数的典型用法是类   使用日志文件和   构造函数用于写入   该文件的条目。

  •   
  • 在为
    创建包装类时,静态构造函数也很有用   非托管代码,当构造函数为   可以调用LoadLibrary方法。

  •   
  • 如果静态构造函数抛出异常,则运行时将不会   再次调用它和类型   将继续未初始化   应用程序域的生命周期   你的程序正在运行。

  •   

最重要的一点是,如果静态构造函数中发生错误,则抛出TypeIntializationException,您无法深入查看有问题的代码行。相反,您必须检查TypeInitializationException的{​​{1}}成员,这是具体原因。

答案 55 :(得分:40)

System.Diagnostics命名空间中的其他一些属性非常有用。

DebuggerBrowsable将允许您隐藏调试器窗口中的变量(我们将其用于公开属性的所有私有后备变量)。除此之外,DebuggerStepThrough使调试器跨过该代码,对于哑属性非常有用(如果可以依赖于C#3.0编译器,则可能应该转换为自动属性)。作为一个例子

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string nickName;
public string NickName    {
    [DebuggerStepThrough]
    get { return nickName; }
    [DebuggerStepThrough]
    set { this.nickName = value; }
}

答案 56 :(得分:39)

C#+ CLR:

  1. Thread.MemoryBarrier:大多数人都不会使用它,并且MSDN上有一些不准确的信息。但如果您知道intricacies,那么您可以进行漂亮的无锁同步。

  2. volatile, Thread.VolatileRead, Thread.VolatileWrite:很少有人能够使用这些,甚至更少的人了解他们避免和引入的所有风险:)。

  3. ThreadStatic变量:过去几年中只有一种情况我发现ThreadStatic变量绝对是神派并且不可或缺。例如,当你想为整个调用链做某事时,它们非常有用。

  4. fixed关键字:当你想要像C ++一样快地访问大型数组的元素时,这是一个隐藏的武器(默认情况下,C#强制执行绑定检查会减慢速度)。

  5. default(typeName)关键字也可以在泛型类之外使用。创建struct的空副本很有用。

  6. 我使用的一个方便功能是DataRow[columnName].ToString()始终返回非空值。如果数据库中的值为NULL,则为空字符串。

  7. 当您希望开发人员注意时,使用Debugger对象会自动中断,即使他/她没有启用异常时自动中断:

  8. 
    #if DEBUG  
        if (Debugger.IsAttached)  
            Debugger.Break();  
    #endif
    
    1. 您可以为复杂丑陋的通用类型添加别名,这样您就不必一次又一次地复制它们。您也可以在一个地方更改该类型。例如,
    2. 
          using ComplicatedDictionary = Dictionary<int, Dictionary<string, object>>;
          ComplicatedDictionary myDictionary = new ComplicatedDictionary();
      

答案 57 :(得分:38)

我说使用某些系统类进行扩展方法非常方便,例如System.Enum,你可以做类似下面的事情......

[Flags]
public enum ErrorTypes : int {
    None = 0,
    MissingPassword = 1,
    MissingUsername = 2,
    PasswordIncorrect = 4
}

public static class EnumExtensions {

    public static T Append<T> (this System.Enum type, T value) where T : struct
    {
        return (T)(ValueType)(((int)(ValueType) type | (int)(ValueType) value));
    }

    public static T Remove<T> (this System.Enum type, T value) where T : struct
    {
        return (T)(ValueType)(((int)(ValueType)type & ~(int)(ValueType)value));
    }

    public static bool Has<T> (this System.Enum type, T value) where T : struct
    {
        return (((int)(ValueType)type & (int)(ValueType)value) == (int)(ValueType)value);
    }

}

...

//used like the following...

ErrorTypes error = ErrorTypes.None;
error = error.Append(ErrorTypes.MissingUsername);
error = error.Append(ErrorTypes.MissingPassword);
error = error.Remove(ErrorTypes.MissingUsername);

//then you can check using other methods
if (error.Has(ErrorTypes.MissingUsername)) {
    ...
}

这只是一个例子 - 方法可以使用更多的工作......

答案 58 :(得分:38)

闭包

由于匿名代表被添加到2.0,我们已经能够开发闭包。它们很少被程序员使用,但提供了很多好处,例如即时代码重用。考虑一下这段代码:

bool changed = false;

if (model.Prop1 != prop1)
{
    changed = true;
    model.Prop1 = prop1;
}
if (model.Prop2 != prop2)
{
    changed = true;
    model.Prop2 = prop2;
}
// ... etc. 

请注意,上面的if语句执行类似的代码片段,但一行代码除外,即设置不同的属性。这可以通过以下内容缩短,其中变化的代码行作为参数输入到Action对象,名称为setAndTagChanged

bool changed = false;
Action<Action> setAndTagChanged = (action) => 
{ 
    changed = true; 
    action(); 
};

if (model.Prop1 != prop1) setAndTagChanged(() => model.Prop1 = prop1);
if (model.Prop2 != prop2) setAndTagChanged(() => model.Prop2 = prop2);

在第二种情况下,闭包允许您在lambda中调整change变量的范围,这是解决此问题的简明方法。

另一种方法是使用另一个未使用的功能,即“等于”二进制赋值运算符。以下代码显示了:

private bool conditionalSet(bool condition, Action action)
{
    if (condition) action();
    return condition;
}

// ...

bool changed = false;
changed |= conditionalSet(model.Prop1 == prop1, () => model.Prop1 = prop1);
changed |= conditionalSet(model.Prop2 == prop2, () => model.Prop2 = prop2);

答案 59 :(得分:36)

我今天刚刚发现了这个 - 我和C#一起工作了5年!

这是namespace alias qualifier

extern alias YourAliasHere;

您可以使用它来加载相同类型的多个版本。这在维护或升级方案中非常有用,在这种情况下,您的类型的更新版本在某些旧代码中不起作用,但您需要将其升级到新版本。 Slap on a namespace alias qualifier,编译器将允许您在代码中使用这两种类型。

答案 60 :(得分:36)

能够使枚举类型的值不是int(默认值)

public enum MyEnum : long
{
    Val1 = 1,
    Val2 = 2
}

此外,您可以为该枚举分配任何数值:

MyEnum e = (MyEnum)123;

答案 61 :(得分:36)

RealProxy允许您为现有类型创建自己的代理。

这是超级先进的,我还没有看到其他人使用它 - 这可能意味着它对大多数人来说也没那么有用 - 但这是其中一件很有趣的事情。

基本上,.NET RealProxy 类允许您为另一种类型创建所谓的透明代理。透明在这种情况下意味着它看起来完全像它的客户端的代理目标对象 - 但它实际上不是:它是您的类的实例,它是从RealProxy派生的。

这使您可以在客户端和在真实目标对象上调用的任何方法或属性之间应用强大而全面的拦截和“中介”服务。将此功能与工厂模式(IoC等)结合使用,您可以回送透明代理而不是真实对象,允许您拦截对真实对象的所有调用,并在每次方法调用之前和之后执行操作。事实上,我相信这是.NET用于跨应用程序域,进程和机器边界进行远程处理的功能:.NET拦截所有访问,将序列化信息发送到远程对象,接收响应,并将其返回到您的代码。

也许一个例子会清楚说明这是如何有用的:我为我作为企业架构师的最后一份工作创建了一个参考服务堆栈,它指定了整个部门中任何新WCF服务的标准内部组合(“堆栈”)。该模型要求(例如)Foo服务实现IDAL<Foo>:的数据访问层创建Foo,读取Foo,更新Foo,删除Foo。服务开发人员使用提供的公共代码(来自我)来定位和加载服务所需的DAL:

IDAL<T> GetDAL<T>(); // retrieve data access layer for entity T

该公司的数据访问策略经常受到性能挑战。作为一名架构师,我无法监视每个服务开发人员,以确保他/她编写了一个高性能的数据访问层。但是我在 GetDAL 工厂模式中可以做的是为请求的DAL创建透明代理(一旦公共服务模型代码找到DLL并加载它),并使用高性能计时API,用于分析对DAL的任何方法的所有调用。然后对落后者进行排名只是通过降低总时间来排序DAL呼叫时间。这种过度开发分析(例如在IDE中)的优点在于它也可以在生产环境中完成,以确保SLA。

以下是我为“实体分析器”编写的测试代码示例,这是为单行创建任何类型的分析代理的常用代码:

[Test, Category("ProfileEntity")]
public void MyTest()
{
    // this is the object that we want profiled.
    // we would normally pass this around and call
    // methods on this instance.
    DALToBeProfiled dal = new DALToBeProfiled();

    // To profile, instead we obtain our proxy
    // and pass it around instead.
    DALToBeProfiled dalProxy = (DALToBeProfiled)EntityProfiler.Instance(dal);

    // or...
    DALToBeProfiled dalProxy2 = EntityProfiler<DALToBeProfiled>.Instance(dal);

    // Now use proxy wherever we would have used the original...
    // All methods' timings are automatically recorded
    // with a high-resolution timer
    DoStuffToThisObject(dalProxy);

    // Output profiling results
    ProfileManager.Instance.ToConsole();
}

同样,这允许您拦截客户端在目标对象上调用的所有方法和属性!在 RealProxy派生的类中,您必须覆盖调用:

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
[SecurityPermission(SecurityAction.LinkDemand, 
    Flags = SecurityPermissionFlag.Infrastructure)] // per FxCop
public override IMessage Invoke(IMessage msg)
{
    IMethodCallMessage msgMethodCall = msg as IMethodCallMessage;
    Debug.Assert(msgMethodCall != null); // should not be null - research Invoke if this trips. KWB 2009.05.28

    // The MethodCallMessageWrapper
    // provides read/write access to the method 
    // call arguments. 
    MethodCallMessageWrapper mc =
        new MethodCallMessageWrapper(msgMethodCall);

    // This is the reflected method base of the called method. 
    MethodInfo mi = (MethodInfo)mc.MethodBase;

    IMessage retval = null;

    // Pass the call to the method and get our return value
    string profileName = ProfileClassName + "." + mi.Name;

    using (ProfileManager.Start(profileName))
    {
        IMessage myReturnMessage =
           RemotingServices.ExecuteMessage(_target, msgMethodCall);

        retval = myReturnMessage;
    }

    return retval;
}

.NET能做什么并不令人着迷?唯一的限制是目标类型必须派生自 MarshalByRefObject 。我希望这对某人有帮助。

答案 62 :(得分:35)

任意嵌套范围{}


1。对于更精细的范围行为

{会员内任何地方} {仅使用大括号} {没有控制声明}

void MyWritingMethod() {

    int sameAge = 35;


    { // scope some work
        string name = "Joe";
        Log.Write(name + sameAge.ToString());
    }


    { // scope some other work
        string name = "Susan";
        Log.Write(name + sameAge.ToString());
    }

    // I'll never mix up Joe and Susan again
}

在大型,混乱或过时的成员(不是说它们应该存在)中,它可以帮助我防止使用错误的变量名称。范围更精细的东西。

2。用于代码美化或视觉语义

例如,此XML编写代码遵循实际生成的XML的缩进级别(即Visual Studio将相应地缩进范围大括号)

XmlWriter xw = new XmlWriter(..);

//<root>
xw.WriteStartElement("root");
{
    //<game>
    xw.WriteStartElement("game");
    {
        //<score>#</score>
        for (int i = 0; i < scores.Length; ++i) // multiple scores
            xw.WriteElementString("score", scores[i].ToString());

    }
    //</game>
    xw.WriteEndElement();
}
//</root>
xw.WriteEndElement();

3。模仿'with'语句

(另一种用于保持临时工作不在主要范围内的用途)
Patrik提供:有时用于模仿C#中的VB“with-statement”。

var somePerson = this.GetPerson();  // whatever 
{ 
    var p = somePerson; 
    p.FirstName = "John"; 
    p.LastName = "Doe"; 
    //... 
    p.City = "Gotham"; 
} 

对于挑剔的程序员。

答案 63 :(得分:34)

没有隐藏,但我认为很多开发人员都没有在可空类型上使用HasValue和Value属性。

        int? x = null;
        int y;
        if (x.HasValue)
            y = x.Value;

答案 64 :(得分:33)

我最喜欢的是

global::

关键字以逃避与我们的第三方代码提供商的命名空间地狱...

示例:

global::System.Collections.Generic.List<global::System.String> myList =
    new global::System.Collections.Generic.List<global::System.String>();

答案 65 :(得分:32)

我已经阅读了所有七页,我错过了这些:

<强>的string.join

我已经看到很多for循环将项目列表转换为带分隔符的字符串。确保不以分隔符开头并且不以分隔符结束总是很痛苦。内置方法使这更容易:

String.Join(",", new String[] { "a", "b", "c"});

评论中的TODO

不是真正的C#功能,更多是Visual Studio功能。当您使用TODO开始发表评论时,它会添加到您的Visual Studio任务列表中(查看 - &gt;任务列表。评论)

// TODO: Implement this!
throw new NotImplementedException();

扩展方法符合泛型

您可以将扩展方法与Generics结合使用,当您考虑本主题前面的技巧时,可以向特定接口添加扩展

public static void Process<T>(this T item) where T:ITest,ITest2 {}

<强> Enumerable.Range

只想要一个整数列表?

Enumerable.Range(0, 15)

我会考虑更多......

答案 66 :(得分:31)

您可以在一个using语句中“使用”多个对象。

using (Font f1= new Font("Arial", 10.0f), f2 = new Font("Arial", 10.0f))
{
    // Use f1 and f2.
}

请注意,已经有一个答案表明您可以这样做:

using (Font f1= new Font("Arial", 10.0f))
using (Font f2 = new Font("Arial", 10.0f))
{    }

与我的不同。

答案 67 :(得分:31)

string.Format()

中的宽度
Console.WriteLine("Product: {0,-7} Price: {1,5}", product1, price1);
Console.WriteLine("Product: {0,-7} Price: {1,5}", product2, price2);

产生

alt text

来自Prabir's Blog | Hidden C# feature

答案 68 :(得分:31)

的typedef

有人发布他们错过了typedef但你可以这样做

using ListOfDictionary = System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, string>>;

并将其声明为

ListOfDictionary list = new ListOfDictionary();

答案 69 :(得分:30)

我喜欢关键字 continue

如果你在一个循环中遇到一个条件并且不想做任何事情而只是推进循环只需坚持“继续;”。

E.g:

foreach(object o in ACollection)
{
  if(NotInterested)
     continue;
}

答案 70 :(得分:28)

我个人最喜欢的两个,我认为很少使用:

  1. Snippets(特别是对于属性,对Visual Studio 2008来说更好)
  2. ObsoleteAttribute

答案 71 :(得分:28)

类似JavaScript的匿名内联函数

返回一个字符串:

var s = new Func<String>(() =>
{
    return "Hello World!";
})();

返回更复杂的对象:

var d = new Func<Dictionary<Int32, String>>(() =>
{
    return new Dictionary<Int32, String>
    {
        { 0, "Foo" },
        { 1, "Bar" },
        { 2, "..." }
    };
})();

真实世界的用例:

var tr = new TableRow();

tr.Cells.AddRange
(
    new[]
    {
        new TableCell { Text = "" },
        new TableCell { Text = "" },
        new TableCell { Text = "" },

        new TableCell
        {
            Text = new Func<String>(() =>
            {
                return @"Result of a chunk of logic, without having to define
                         the logic outside of the TableCell constructor";
            })()
        },

        new TableCell { Text = "" },
        new TableCell { Text = "" }
    }
);

注意:您不能在内联函数的范围内重用变量名。


替代语法

// The one-liner
Func<Int32, Int32, String> Add = (a, b) => Convert.ToString(a + b);

// Multiple lines
Func<Int32, Int32, String> Add = (a, b) =>
{
    var i = a + b;

    return i.ToString();
};

// Without parameters
Func<String> Foo = () => "";

// Without parameters, multiple lines
Func<String> Foo = () =>
{
    return "";
};

缩短字符串并添加水平省略号...

Func<String, String> Shorten = s => s.Length > 100 ? s.Substring(0, 100) + "&hellip;" : s;

答案 72 :(得分:28)

使用语句嵌套

通常我们这样做:

StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter()) {
    using (IndentedTextWriter itw = new IndentedTextWriter(sw)) {
        ... 
    }
}

但我们可以这样做:

StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter())
using (IndentedTextWriter itw = new IndentedTextWriter(sw)) {
    ... 
}

答案 73 :(得分:28)

@lomaxx我前几天也学到了(同时我学到了你的提示)是你现在可以在同一个属性上拥有不同的访问级别:

public string Name { get; private set;}

这样只有类本身才能设置Name属性。

public MyClass(string name) { Name = name; }

答案 74 :(得分:28)

完全访问调用堆栈:

public static void Main()
{
  StackTrace stackTrace = new StackTrace();           // get call stack
  StackFrame[] stackFrames = stackTrace.GetFrames();  // get method calls (frames)

  // write call stack method names
  foreach (StackFrame stackFrame in stackFrames)
  {
    Console.WriteLine(stackFrame.GetMethod().Name);   // write method name
  }
}

所以,如果你拿第一个 - 你知道你在做什么功能。如果你正在创建一个辅助跟踪功能 - 在最后一个之前取一个 - 你就会知道你的来电者。

答案 75 :(得分:27)

轻松确定变量声明的类型(来自my answer):

using System;
using System.Collections.Generic;

static class Program
{
    public static Type GetDeclaredType<T>(T x)
    {
        return typeof(T);
    }

    // Demonstrate how GetDeclaredType works
    static void Main(string[] args)
    {
        IList<string> iList = new List<string>();
        List<string> list = null;

        Console.WriteLine(GetDeclaredType(iList).Name);
        Console.WriteLine(GetDeclaredType(list).Name);
    }
}

结果:

IList`1
List`1

名称(借鉴"Get variable name"):

static void Main(string[] args)
{
    Console.WriteLine("Name is '{0}'", GetName(new {args}));
    Console.ReadLine();
}

static string GetName<T>(T item) where T : class
{
    var properties = typeof(T).GetProperties();
    return properties[0].Name;
}

结果:Name is 'args'

答案 76 :(得分:27)

还有ThreadStaticAttribute为每个线程创建一个唯一的静态字段,因此您可以拥有强类型的线程本地存储。

即使扩展方法不是那么秘密(LINQ基于它们),对于实用程序帮助程序方法来说它们的实用性和可读性可能并不那么明显:

//for adding multiple elements to a collection that doesn't have AddRange
//e.g., collection.Add(item1, item2, itemN);
static void Add<T>(this ICollection<T> coll, params T[] items)
 { foreach (var item in items) coll.Add(item);
 }

//like string.Format() but with custom string representation of arguments
//e.g., "{0} {1} {2}".Format<Custom>(c=>c.Name,"string",new object(),new Custom())
//      result: "string {System.Object} Custom1Name"
static string Format<T>(this string format, Func<T,object> select, params object[] args)
 { for(int i=0; i < args.Length; ++i)
    { var x = args[i] as T;
      if (x != null) args[i] = select(x);
    }
   return string.Format(format, args);
 }

答案 77 :(得分:27)

它实际上并不是一个C#隐藏功能,但我最近发现了WeakReference class并被它吹走了(尽管这可能会因为它帮助我找到particular problem of mine的解决方案而有所偏差...)

答案 78 :(得分:27)

一行按需字段初始化:

public StringBuilder Builder
{
    get { return _builder ?? (_builder = new StringBuilder()); }
}

我不确定我对C#支持赋值表达式的看法,但是嘿,它就在那里: - )

答案 79 :(得分:26)

从C / C ++迁移的程序员可能会错过这个:

在C#中,%(模数运算符)适用于浮点数!

答案 80 :(得分:26)

Environment.UserInteractive属性。

  

UserInteractive属性报告   对于Windows进程或   IIS之类的服务没有运行   用户界面。如果这个属性是   false,不显示模态对话框或   消息框因为没有   用户的图形用户界面   与...互动。

答案 81 :(得分:26)

AppDomain.UnhandledException Event也是被隐藏的候选人。

  

此事件提供未捕获异常的通知。它允许应用程序在系统默认处理程序向用户报告异常并终止应用程序之前记录有关异常的信息。如果有足够的有关应用程序状态的信息,则可以采取其他措施 - 例如保存程序数据以便以后恢复。建议小心,因为在未处理异常时程序数据可能会损坏。

我们可以看到,即使在这个网站上,也有很多人想知道为什么他们的应用程序没有启动,为什么崩溃等等。AppDomain.UnhandledException事件对于这种情况非常有用,因为它提供了可能性至少记录应用程序失败的原因。

答案 82 :(得分:25)

C#?? null合并运算符 -

不是真的隐藏,但很少使用。可能是因为很多开发人员在看到条件时会跑一英里?操作员,所以当他们看到这个时他们跑两个。使用:

string mystring = foo ?? "foo was null"

而不是

string mystring;
if (foo==null)
    mystring = "foo was null";
else
    mystring = foo;

答案 83 :(得分:25)

#if DEBUG 预处理器指令。它很有用 测试和调试(虽然我通常喜欢去 单元测试路线)。

string customerName = null;
#if DEBUG
  customerName = "Bob"
#endif

如果将Visual Studio设置为,它将仅执行代码块 在“调试”模式下编译。否则代码块将是 编译器忽略(在Visual Studio中显示为灰色)。

答案 84 :(得分:25)

我没有找到任何使用string.Join的人使用分隔符连接字符串。每个人都在写同样丑陋的for-loop

var sb = new StringBuilder();
var count = list.Count();
for(int i = 0; i < count; i++)
{
  if (sb.Length > 0) sb.Append(seperator);
  sb.Append(list[i]);
}

return sb.ToString();

而不是

return string.Join(separator, list.ToArray());

答案 85 :(得分:24)

部分方法

Charlie Calvert explains partial methods on his blog

Scott Cate has a nice partial method demo here

  1. 代码生成类(LINQ to SQL,EF)
  2. 中的可扩展性
  3. 如果没有实现,则不会编译到dll中(使用.NET Reflector检查)

答案 86 :(得分:24)

C#中有一些与TypedReference未记录的类相关的隐藏关键字和功能。以下关键字未记录:

  • __makeref
  • __reftype
  • __refvalue
  • __arglist

使用示例:

// Create a typed reference
int i = 1;
TypedReference tr1 = __makeref(i);
// Get the type of a typed reference
Type t = __reftype(tr1);
// Get the value of a typed referece
int j = __refvalue(tr1, int); 
// Create a method that accepts and arbitrary number of typed references
void SomeMethod(__arglist) { ...
// Call the method
int x = 1;
string y = "Foo";
Object o = new Object();
SomeMethod(__arglist(x,y,o));
// And finally iterate over method parameters
void SomeMethod(__arglist) {
    ArgIterator ai = new ArgIterator(__arglist);
while(ai.GetRemainingCount() >0)
{
      TypedReference tr = ai.GetNextArg();
      Console.WriteLine(TypedReference.ToObject(tr));
}}

答案 87 :(得分:24)

truefalse运营商真的很奇怪。

可以找到更全面的示例here

编辑:有相关问题What’s the false operator in C# good for?

答案 88 :(得分:23)

我发现只有少数开发者知道这个功能。

如果您需要一种通过某种界面值类型变量(通过此值类型实现)的方法,则在方法调用期间很容易避免装箱

示例代码:

using System;
using System.Collections;

interface IFoo {
    void Foo();
}
struct MyStructure : IFoo {
    public void Foo() {
    }
}
public static class Program {
    static void MethodDoesNotBoxArguments<T>(T t) where T : IFoo {
        t.Foo();
    }
    static void Main(string[] args) {
        MyStructure s = new MyStructure();
        MethodThatDoesNotBoxArguments(s);
    }
}

IL代码不包含任何框指令:

.method private hidebysig static void  MethodDoesNotBoxArguments<(IFoo) T>(!!T t) cil managed
{
  // Code size       14 (0xe)
  .maxstack  8
  IL_0000:  ldarga.s   t
  IL_0002:  constrained. !!T
  IL_0008:  callvirt   instance void IFoo::Foo()
  IL_000d:  ret
} // end of method Program::MethodDoesNotBoxArguments

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       15 (0xf)
  .maxstack  1
  .locals init ([0] valuetype MyStructure s)
  IL_0000:  ldloca.s   s
  IL_0002:  initobj    MyStructure
  IL_0008:  ldloc.0
  IL_0009:  call       void Program::MethodDoesNotBoxArguments<valuetype MyStructure>(!!0)
  IL_000e:  ret
} // end of method Program::Main

参见Richter, J. CLR via C#,第2版,第14章:接口,关于泛型和接口约束的部分。

另见my answer另一个问题。

答案 89 :(得分:22)

已经提到了所有很酷的。不确定这个是否众所周知

C#property / field构造函数初始化:

var foo = new Rectangle() 
{ 
    Fill = new SolidColorBrush(c), 
    Width = 20, 
    Height = 20 
};

这将创建矩形,并设置列出的属性。

我注意到了一些有趣的东西 - 你可以在属性列表的末尾加一个逗号,而不会出现语法错误。所以这也是有效的:

var foo = new Rectangle() 
{ 
    Fill = new SolidColorBrush(c), 
    Width = 20, 
    Height = 20,
};

答案 90 :(得分:21)

有些人提到使用块,但我认为它们比人们意识到的要有用得多。把它们想象成穷人的AOP工具。我有许多简单的对象,它们在构造函数中捕获状态,然后在 Dispose()方法中恢复它。这允许我在中使用块包装一段功能,并确保在最后恢复状态。例如:

using(new CursorState(this, BusyCursor));
{
    // Do stuff
}

CursorState 捕获表单使用的当前游标,然后设置表单以使用提供的游标。最后它恢复原始光标。我做了很多这样的事情,例如在刷新之前捕获网格上的选择和当前行等等。

答案 91 :(得分:21)

基于这个帖子应该被称为“你最不知道的关于C#的事情,直到最近,尽管你已经知道了所有事情”,我的个人特征是异步代表。

直到我读到Jeff Richter的C#/ CLR书(优秀的书,每个人都在读.NET)我不知道你可以使用BeginInvoke / {来调用任何委托{1}}。我倾向于做很多EndInvoke次调用(我猜这很像是委托ThreadPool.QueueUserWorkItem在内部做的事情),但是有时添加标准化的连接/集合点模式可能非常有用。 / p>

答案 92 :(得分:21)

关于事件处理程序的另一个注意事项:您可以像这样简单地创建一个提升扩展方法:

public static class EventExtensions {
    public static void Raise<T>(this EventHandler<T> @event, 
                                object sender, T args) where T : EventArgs {
        if(@event!= null) {
            @event(sender, args);
        }
    }
}

然后你可以用它来举起事件:

public class MyImportantThing {
    public event EventHandler<MyImportantEventEventArgs> SomethingHappens;
    ...
    public void Bleh() {
        SomethingHappens.Raise(this, new MyImportantEventEventArgs { X=true });
    }
}

此方法具有强制执行编码标准(使用EventHandler<>)的附加优势。

一遍又一遍地编写相同的功能是没有意义的。也许下一版本的C#最终会有一个InlineAttribute,可以放在扩展方法上,并使编译器内联方法定义(这将使这种方式接近标准,并且最快)。

编辑:根据注释

删除扩展方法中的临时变量

答案 93 :(得分:20)

我参加这个派对已经很晚了,所以我的第一选择已经开始了。但我没有看到有人提到这个宝石:

Parallel Extensions to the .NET Framework

使用Parallel.ForEach

替换为Parallel.For或foreach

平行样本:
在您看来,一秒钟内可以创建多少个CLR对象? enter image description here
见下面的例子:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ObjectInitSpeedTest
{
   class Program
   {
       //Note: don't forget to build it in Release mode.
       static void Main()
       {
           normalSpeedTest();           
           parallelSpeedTest();

           Console.ForegroundColor = ConsoleColor.White;
           Console.WriteLine("Press a key ...");
           Console.ReadKey();
       }

       private static void parallelSpeedTest()
       {
           Console.ForegroundColor = ConsoleColor.Yellow;
           Console.WriteLine("parallelSpeedTest");

           long totalObjectsCreated = 0;
           long totalElapsedTime = 0;

           var tasks = new List<Task>();
           var processorCount = Environment.ProcessorCount;

           Console.WriteLine("Running on {0} cores", processorCount);

           for (var t = 0; t < processorCount; t++)
           {
               tasks.Add(Task.Factory.StartNew(
               () =>
               {
                   const int reps = 1000000000;
                   var sp = Stopwatch.StartNew();
                   for (var j = 0; j < reps; ++j)
                   {
                       new object();
                   }
                   sp.Stop();

                   Interlocked.Add(ref totalObjectsCreated, reps);
                   Interlocked.Add(ref totalElapsedTime, sp.ElapsedMilliseconds);
               }
               ));
           }

           // let's complete all the tasks
           Task.WaitAll(tasks.ToArray());

           Console.WriteLine("Created {0:N} objects in 1 sec\n", (totalObjectsCreated / (totalElapsedTime / processorCount)) * 1000);
       }

       private static void normalSpeedTest()
       {
           Console.ForegroundColor = ConsoleColor.Green;
           Console.WriteLine("normalSpeedTest");

           const int reps = 1000000000;
           var sp = Stopwatch.StartNew();
           sp.Start();
           for (var j = 0; j < reps; ++j)
           {
               new object();
           }
           sp.Stop();

           Console.WriteLine("Created {0:N} objects in 1 sec\n", (reps / sp.ElapsedMilliseconds) * 1000);
       }
   }
}

答案 94 :(得分:20)

Atrribute Targets

每个人都见过一个。基本上,当你看到这个:

[assembly: ComVisible(false)]

该属性的“assembly:”部分是目标。在这种情况下,该属性将应用于程序集,但还有其他属性:

[return: SomeAttr]
int Method3() { return 0; } 

在此示例中,属性应用于返回值。

答案 95 :(得分:20)

好吧,看起来很明显,但我想提一下Object.Equals方法(静态方法,有两个参数)。

我很确定很多人甚至不知道它,或者忘记了它,但在某些情况下它确实有用。例如,当您想比较两个对象是否相等时,不知道它们是否为空。你写了多少次这样的东西:

if ((x == y) || ((x != null && y != null) && x.Equals(y)))
{
    ...
}

什么时候可以写:

if (Object.Equals(x, y))
{
    ...
}

Object.Equals实际上与第一个代码示例完全相同)

答案 96 :(得分:20)

string.Empty

我知道这不是幻想(荒唐奇怪),但我一直使用它而不是“”。

直到有人告诉你它在那里时才会隐藏起来。

答案 97 :(得分:20)

IObservable 怎么样?

几乎每个人都知道IEnumerable,但他们的数学对偶似乎是未知的IObservable。也许是因为它在.NET 4中的新功能。

它所做的不是提取信息(如可枚举的信息),而是将信息推送给观察者的订阅者。

Rx extensions一起,它将改变我们处理事件的方式。只是为了说明它有多强大,请查看一个非常简短的例子here

答案 98 :(得分:20)

我喜欢的一个很棒的课程是System.Xml.XmlConvert,它可用于从xml标签中读取值。特别是,如果我从xml属性或元素中读取布尔值,我使用

bool myFlag  = System.Xml.XmlConvert.ToBoolean(myAttribute.Value);

注意:由于xml中的布尔类型除了“true”和“false”之外还接受1和0作为有效值,因此在这种情况下使用字符串比较容易出错。

答案 99 :(得分:20)

道歉这么晚,我是Stack Overflow的新手,所以错过了之前的机会。

我发现EventHandler<T>是未充分利用的框架的一个重要特性。

我遇到的大多数C#开发人员在定义自定义事件时仍定义自定义事件处理程序委托,这根本就不再需要了。

而不是:

public delegate void MyCustomEventHandler(object sender, MyCustomEventArgs e);

public class MyCustomEventClass 
{
    public event MyCustomEventHandler MyCustomEvent;
}
你可以去:

public class MyCustomEventClass 
{
    public event EventHandler<MyCustomEventArgs> MyCustomEvent;
}

这更简洁,而且你不会陷入是否将委托放在包含事件的类的.cs文件或EventArgs派生类的困境。

答案 100 :(得分:19)

不是真的隐藏,但很有用。如果你有一个enum flags,你可以使用shift-left来使事情变得更清晰。 e.g。

[Flags]
public enum ErrorTypes {
    None              = 0,
    MissingPassword   = 1 << 0,
    MissingUsername   = 1 << 1,
    PasswordIncorrect = 1 << 2 
}

答案 101 :(得分:19)

C#3.0的LINQ查询理解是完整的monadic理解 a la Haskell(实际上它们是由Haskell的设计师之一设计的)。它们适用于“LINQ模式”之后的任何泛型类型,并允许您使用纯monadic函数样式进行编写,这意味着所有变量都是不可变的(就好像您使用的唯一变量是IDisposable s和使用 foreach 语句中的IEnumerable。这有助于将变量声明保持在接近它们使用的位置,并确保明确声明所有副作用(如果有的话)。

 interface IFoo<T>
  { T Bar {get;}
  }

 class MyFoo<T> : IFoo<T> 
  { public MyFoo(T t) {Bar = t;}
    public T Bar {get; private set;} 
  }

 static class Foo 
  { public static IFoo<T> ToFoo<T>(this T t) {return new MyFoo<T>(t);}

    public static void Do<T>(this T t, Action<T> a) { a(t);}

    public static IFoo<U> Select<T,U>(this IFoo<T> foo, Func<T,U> f) 
     { return f(foo.Bar).ToFoo();
     }
  }

 /* ... */

 using (var file = File.OpenRead("objc.h"))
 { var x = from f in file.ToFoo()
           let s = new Scanner(f)
           let p = new Parser {scanner = s}
           select p.Parse();

   x.Do(p => 
    { /* drop into imperative code to handle file 
         in Foo monad if necessary */      
    });

 }

答案 102 :(得分:19)

我看到很多人复制了Nullable<T>.GetValueOrDefault(T)的功能。

答案 103 :(得分:18)

我最喜欢的属性:InternalsVisibleTo

在程序集级别,您可以声明另一个程序集可以看到您的内部。出于测试目的,这绝对是美妙的。

将它粘贴在AssemblyInfo.cs或同等版本中,您的测试程序集就可以完全访问需要测试的所有内部资源。

[assembly: InternalsVisibleTo("MyLibrary.Test, PublicKey=0024...5c042cb")]

如您所见,测试装配必须具有a strong name才能获得被测装配的信任。

适用于.Net Framework 2.0 +,Compact Framework 2.0+和XNA Framework 1.0 +。

答案 104 :(得分:17)

extern alias关键字引用具有相同完全限定类型名称的两个版本的程序集。

答案 105 :(得分:17)

您可以使用{ }括号限制变量的生命周期和范围。

{
    string test2 = "3";
    Console.Write(test2);
}

Console.Write(test2); //compile error

test2仅存在于括号内。

答案 106 :(得分:17)

需要返回一个空的IEnumerable吗?

public IEnumerable<T> GetEnumerator(){
  yield break;
}

答案 107 :(得分:17)

我喜欢使用@字符进行SQL查询。它使sql保持良好和格式化,而不必用字符串分隔符包围每一行。

string sql = @"SELECT firstname, lastname, email
               FROM users
               WHERE username = @username AND password = @password";

答案 108 :(得分:16)

您可以在枚举中存储颜色。

public enum MyEnumColors : uint
{
    Normal          = 0xFF9F9F9F,
    Active          = 0xFF8EA98A,
    Error           = 0xFFFF0000
}

答案 109 :(得分:16)

能够使用LINQ表达式执行强类型反射:

static void Main(string[] args)
{
  var domain = "matrix";
  Check(() => domain);
  Console.ReadLine();
}

static void Check<T>(Expression<Func<T>> expr)
{
  var body = ((MemberExpression)expr.Body);
  Console.WriteLine("Name is: {0}", body.Member.Name);
  Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
   .GetValue(((ConstantExpression)body.Expression).Value));
}

// output:
// Name is: 'domain'
// Value is: 'matrix'

更多详细信息,请访问How to Find Out Variable or Parameter Name in C#?

答案 110 :(得分:15)

我经常遇到将通用参数对象持久保存到基类中的视图状态的需要。

public abstract class BaseListControl<ListType,KeyType,ParameterType>
                 : UserControl 
                 where ListType : BaseListType
                 && ParameterType : BaseParameterType, new
{

    private const string viewStateFilterKey = "FilterKey";

    protected ParameterType Filters
    {
        get
        {
            if (ViewState[viewStateFilterKey] == null)
                ViewState[viewStateFilterKey]= new ParameterType();

            return ViewState[viewStateFilterKey] as ParameterType;
        }
        set
        {
            ViewState[viewStateFilterKey] = value;
        }
    }

}

用法:

private void SomeEventHappened(object sender, EventArgs e)
{
    Filters.SomeValue = SomeControl.SelectedValue;
}

private void TimeToFetchSomeData()
{
    GridView.DataSource = Repository.GetList(Filters);
}

“ParameterType:BaseParameterType,new where”这个小技巧让它真正起作用。

在我的基类中使用此属性,我可以自动处理分页,设置过滤器值以过滤网格视图,使排序变得非常简单等等。

我真的只是说仿制药可以成为一个非常强大的野兽。

答案 111 :(得分:15)

您可以添加和删除代码较少的代理。

通常的方式:

handler += new EventHandler(func);

减少打字方式:

handler += func;

答案 112 :(得分:15)

您可以在C#名称中使用任何Unicode字符,例如:

public class MyClass
{
    public string Hårføner()
    {
        return "Yes, it works!";
    }
}

您甚至可以使用Unicode转义符。这一个等同于上面的内容:

public class MyClass
{
    public string H\u00e5rføner()
    {
        return "Yes, it (still) works!";
    }
}

答案 113 :(得分:15)

在FlagAttribute和enum 中使用“〜”运算符 有时我们会使用带有枚举的Flag属性来对枚举执行按位操作。

 [Flags]
 public enum Colors
 {
    None  = 0,
    Red   = 1,
    Blue  = 2,
    White = 4,
    Black = 8,
    Green = 16,
    All   = 31 //It seems pretty bad...
 }

请注意,枚举中选项“All”的值非常奇怪 而不是我们可以使用带有标记枚举的“〜”运算符。

 [Flags]
 public enum Colors
 {
    None  = 0,
    Red   = 1,
    Blue  = 2,
    White = 4,
    Black = 8,
    Green = 16,
    All   = ~0 //much better now. that mean 0xffffffff in default.
 }

答案 114 :(得分:15)

fixed声明

此语句可防止垃圾收集器重定位可移动变量。 Fixed也可用于创建固定大小的缓冲区。

  

fixed语句设置一个指向托管变量的指针,并在执行语句时设置“引脚”变量。

stackalloc

stackalloc在堆栈上分配一块内存。

答案 115 :(得分:15)

也很有用,但不常用:Constrained Execution Regions

BCL团队博客引用:

  

约束执行区域(CER)   存在是为了帮助开发人员写她   代码以保持一致性。 CLR   不保证开发者的   代码是正确的,但CLR确实如此   提升所有运行时引发的   失败点(即异步异常)   在代码运行之前,或者   完成之后。结合   对开发人员的限制   加入CER,这些都是有用的方法   做出强有力的保证   你的代码是否会执行。 CER的   热切地准备,意味着   当我们看到一个时,我们会急切地JIT   在其中找到的任何代码   静态可发现的调用图。   如果CLR的主机关心堆栈   溢出,我们将探讨一些数额   堆栈空间也是如此(尽管也许   没有足够的堆栈空间   任意方法*)。我们也拖延了   线程中止,直到CER有   跑完了。

以原子方式对数据结构的多个字段进行编辑时非常有用。因此,对象进行交易很有帮助。

CriticalFinalizerObject似乎也被隐藏了(至少谁没有编写不安全的代码)。 CriticalFinalizerObject保证垃圾收集将执行终结器。在分配时,终结器及其调用图是预先准备的。

答案 116 :(得分:15)

枚举上的FlagsAttribute怎么样?它允许您执行按位操作...让我永远地了解如何在.NET中进行按位操作。

答案 117 :(得分:14)

我在Stack Overflow上只学到的一个功能是能够在返回参数上设置属性。

[AttributeUsage( AttributeTargets.ReturnValue )]
public class CuriosityAttribute:Attribute
{
}

public class Bar
{
    [return: Curiosity]
    public Bar ReturnANewBar()
    {
        return new Bar();
    }
}

对我来说,这确实是一个隐藏的功能: - )

答案 118 :(得分:14)

ConditionalAttribute

允许您告诉编译器在特定条件下省略对使用该属性标记的方法的调用(#define)。

省略方法调用的事实也意味着不评估其参数。这非常方便,它允许您在Debug.Assert()中调用昂贵的验证函数,而不用担心它们会减慢您的发布版本。

答案 119 :(得分:14)

您可以将几个属性放在一对方括号中:

    [OperationContract, ServiceKnownType(typeof(Prism)), ServiceKnownType(typeof(Cuboid))]
    Shape GetShape();

答案 120 :(得分:14)

标记我的终端区域......

#region stuff1
 #region stuff1a
 //...
 #endregion stuff1a
#endregion stuff1

答案 121 :(得分:14)

定义自定义属性时,可以将它们与[MyAttAttribute]或[MyAtt]一起使用。 当两个着作都存在类时,就会发生编译错误。

@ special字符可用于区分它们:

[AttributeUsage(AttributeTargets.All)]
public class X: Attribute
{}

[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
{}

[X]      // Error: ambiguity
class Class1 {}

[XAttribute]   // Refers to XAttribute
class Class2 {}

[@X]      // Refers to X
class Class3 {}

[@XAttribute]   // Refers to XAttribute
class Class4 {}

答案 122 :(得分:14)

当一个类实现INotifyPropertyChanged并且您想要通知绑定系统(WPF,Silverlight等)时,对象(ViewModel)的多个绑定属性已更改,您可以使用 null String.Empty

这在MSDN中有记录,但代码示例和文章通常不能解释这种可能性。我发现它非常有用。

public class BoundObject : INotifyPropertyChanged {

    private int _value;
    private string _text;

    public event PropertyChangedEventHandler PropertyChanged;

    public int Value {
        get {
            return _value;
        }
        set {
            if (_value != value) {
                _value = value;
                OnPropertyChanged("Value");
            }
        }
    }

    public string Text {
        get {
            return _text;
        }
        set {
            if (_text != value) {
                _text = value;
                OnPropertyChanged("Text");
            }
        }
    }

    public void Init(){
        _text = "InitialValue";
        _value = 1;
        OnPropertyChanged(string.Empty);
    }

    public void Reset() {
        _text = "DefaultValue";
        _value = 0;
        OnPropertyChanged(string.Empty);
    }

    private void OnPropertyChanged(string propertyName) {
        PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);

        if (PropertyChanged != null) {
            PropertyChanged(this, e);
        }
    }
}

答案 123 :(得分:13)

FlagsAttribute,在使用枚举制作位掩码时很小但nice feature

[Flags]
public enum ConfigOptions
{
    None    = 0,
    A       = 1 << 0,
    B       = 1 << 1,
    Both    = A | B
}

Console.WriteLine( ConfigOptions.A.ToString() );
Console.WriteLine( ConfigOptions.Both.ToString() );
// Will print:
// A
// A, B

答案 124 :(得分:13)

如何使用它:

#if DEBUG
            Console.Write("Debugging");
#else
            Console.Write("Final");
#endif

当您使用DEBUG定义编译解决方案时,它将输出“Debugging”。

如果您的编译设置为Release,它将写入“Final”。

答案 125 :(得分:13)

直到最近我还没有开始真正欣赏“使用”块。他们让事情变得更加整洁:)

答案 126 :(得分:13)

使用LINQ轻松实现眼睛/浓缩ORM映射

考虑下表:

[MessageId] INT,
[MessageText] NVARCHAR(MAX)
[MessageDate] DATETIME

......而这个结构:

struct Message
{
    Int32 Id;
    String Text;
    DateTime Date;
}



而不是做一些事情:

List<Message> messages = new List<Message>();

foreach (row in DataTable.Rows)
{
    var message = new Message
    {
        Id = Convert.ToInt32(row["MessageId"]),
        Text = Convert.ToString(row["MessageText"]),
        Date = Convert.ToDateTime(row["MessageDate"])
    };

    messages.Add(message);
}

你可以使用LINQ并用更少的代码行做同样的事情,在我看来;更多风格。像这样:

var messages = DataTable.AsEnumerable().Select(r => new Message
{
    Id = Convert.ToInt32(r["MessageId"]),
    Text = Convert.ToString(r["MessageText"]),
    Date = Convert.ToDateTime(r["MessageDate"])
}).ToList();

这种方法可以嵌套,就像循环一样。

答案 127 :(得分:13)

工厂方法的类型推断

我不知道这是否已经发布(我扫描了第一篇文章,找不到它)。

最好用一个例子来说明,假设你有这个类(模拟一个元组),试图展示使这成为可能的所有语言特征,我将逐步完成它。

public class Tuple<V1, V2> : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
      this.v1 = v1;
      this.v2 = v2;
    }
}

每个人都知道如何创建它的实例,例如:

Tuple<int, string> tup = new Tuple<int, string>(1, "Hello, World!");

不完全是火箭科学,现在我们当然可以将变量的类型声明更改为 var ,如下所示:

var tup = new Tuple<int, string>(1, "Hello, World!");

仍然众所周知,这里有一个带有类型参数的静态方法,每个人都应该熟悉:

public static void Create<T1, T2>()
{
    // stuff
}

再次熟悉它就是这样做的:

Create<float, double>();

大多数人不知道的是,如果泛型方法的参数包含它所需的所有类型,则可以推断它们,例如:

public static void Create<T1, T2>(T1 a, T2 b)
{
    // stuff
}

这两个电话是相同的:

Create<float, string>(1.0f, "test");
Create(1.0f, "test");

因为T1和T2是从您传递的参数推断出来的。将这些知识与var关键字相结合,我们可以通过添加静态方法的第二个静态类,例如:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

达到这个效果:

var tup = Tuple.Create(1, "Hello, World!");

这意味着:变量“tup”的类型,“Create”的类型参数和“Create”的返回值都是从作为参数传递给Create

完整代码如下所示:

public abstract class Tuple
{
    public static Tuple<V1, V2> Create<V1, V2>(V1 v1, V2 v2)
    {
        return new Tuple<V1, V2>(v1, v2);
    }
}

public class Tuple<V1, V2> : Tuple
{
    public readonly V1 v1;
    public readonly V2 v2;

    public Tuple(V1 v1, V2 v2)
    {
        this.v1 = v1;
        this.v2 = v2;
    }
}

// Example usage:
var tup = Tuple.Create(1, "test");

它为您提供了完全类型推断的工厂方法!

答案 128 :(得分:13)

我正在成为扩展方法的忠实粉丝,因为它们可以为现有代码或无法编辑的代码添加许多想要的功能。我最喜欢的一个是我现在所做的一切是为了string.IsNullOrEmpty()

public static class Strings
{
    public static bool IsNullOrEmpty(this string value)
    {
        return string.IsNullOrEmpty(value);
    }
}

这可以让你有点像这样缩短你的代码

var input = Console.ReadLine();
if (input.IsNullOrEmpty())
{
    Console.WriteLine("try again");
}

答案 129 :(得分:13)

Lambda表达式

Func<int, int, int> add = (a, b) => (a + b);

模糊字符串格式

Console.WriteLine("{0:D10}", 2); // 0000000002

Dictionary<string, string> dict = new Dictionary<string, string> { 
    {"David", "C#"}, 
    {"Johann", "Perl"}, 
    {"Morgan", "Python"}
};

Console.WriteLine( "{0,10} {1, 10}", "Programmer", "Language" );

Console.WriteLine( "-".PadRight( 21, '-' ) );

foreach (string key in dict.Keys)
{
    Console.WriteLine( "{0, 10} {1, 10}", key, dict[key] );             
}

答案 130 :(得分:12)

switch - case可以通过case中没有代码(请参阅case 0)或使用特殊goto case(请参阅case 1)或goto default(请参阅case 2)表单:

switch (/*...*/) {
    case 0: // shares the exact same code as case 1
    case 1:
        // do something
        goto case 2;
    case 2:
        // do something else
        goto default;
    default:
        // do something entirely different
        break;
}

答案 131 :(得分:12)

我能想到的一对夫妇:

[field: NonSerialized()]
public EventHandler event SomeEvent;

这可以防止事件被序列化。 'field:'表示该属性应该应用于事件的后备字段。

另一个鲜为人知的功能是覆盖add / remove事件处理程序:

public event EventHandler SomeEvent
{
    add
    {
        // ...
    }

    remove
    {
        // ...
    }
}

答案 132 :(得分:12)

如果方法参数实现了两个接口,则可以使用泛型来检查(编译时):

interface IPropA 
{
    string PropA { get; set; } 
}

interface IPropB 
{
    string PropB { get; set; }
}

class TestClass 
{
    void DoSomething<T>(T t) where T : IPropA, IPropB 
    {
        MessageBox.Show(t.PropA);
        MessageBox.Show(t.PropB);
    }
}

与从基类和接口继承的参数相同。

答案 133 :(得分:12)

我错过了很长时间的东西: 你可以用

来比较字符串
"string".equals("String", StringComparison.InvariantCultureIgnoreCase)

而不是:

"string".ToLower() == "String".ToLower();

答案 134 :(得分:11)

  1. 我还无法发表评论,但请注意,默认情况下,Visual Studio 2008会自动切换属性,因此在这种情况下不再需要DebuggerStepThrough属性。

  2. 另外,我没有注意到有人展示如何声明一个无参数的lambda(对于实现Action&lt;&gt;非常有用)

    () => DoSomething(x);

  3. 你还应该阅读关闭 - 我不够聪明,无法正确解释它们。但基本上它意味着编译器会做一些聪明的事情,以便即使在创建lambda之后它超出范围,代码行中的x仍然可以工作。

    1. 我最近也发现你可以假装忽略一个lambda参数:

      (e, _) => DoSomething(e)

    2. 它并不是真的忽略它,只是_是一个有效的标识符。所以你不能忽略这两个参数,但我认为这是一种表达我们不关心该参数的简洁方法(通常是.Empty的EventArgs。

答案 135 :(得分:11)

委托语法已经在C#的连续版本中发展,但我仍然觉得它们很难记住。幸运的是,Action<>Func<>代表很容易记住。

例如:

  • Action<int>是一个委托方法,它接受一个int参数并返回void。
  • Func<int>是一个不带参数的委托方法,返回一个int。
  • Func<int, bool>是一个委托方法,它接受一个int参数并返回一个bool。

这些功能是在.NET Framework 3.5版本中引入的。

答案 136 :(得分:11)

可以在null上调用扩展方法;这不会导致NullReferenceException被抛出。

示例应用程序:您可以为名为ToString()的{​​{1}}定义替代方案,该方案将在ToStringOrEmpty()上调用时返回空字符串。

答案 137 :(得分:11)

有些运算符用于在声明的类和一个或多个任意类之间执行implicitexplicit用户定义的类型转换。 implicit运算符有效地允许模拟赋值运算符的重载,这在C ++等语言中是可能的,而不是C#。

它似乎不是经常遇到的功能,但它实际上在LINQ to XMLSystem.Xml.Linq)库中使用,您可以在其中隐式地将字符串转换为{{1对象。例如:

XName

我在此article中发现了有关如何在C#中模拟多重继承的功能。

答案 138 :(得分:11)

我喜欢这样一个事实:我可以在普通的旧版.NET 2.0上使用LINQ来对象(即不需要在任何地方安装.NET 3.5)。您所需要的只是所有查询运算符扩展方法的实现 - 请参阅LINQBridge

答案 139 :(得分:10)

嵌套类可以访问外部类的私有成员。

public class Outer
{
    private int Value { get; set; }

    public class Inner
    {
        protected void ModifyOuterMember(Outer outer, int value)
        {
            outer.Value = value;
        }
    }
}

现在,与上述功能一起,您也可以从嵌套类继承,就像它们是顶级类一样,如下所示。

public class Cheater : Outer.Inner
{
    protected void MakeValue5(Outer outer)
    {
        ModifyOuterMember(outer, 5);
    }
}

这些功能允许一些有趣的可能性,只要通过隐藏的类提供对特定成员的访问。

答案 140 :(得分:10)

您可以使用以下方法更改舍入方案:

var value = -0.5;
var value2 = 0.5;
var value3 = 1.4;

Console.WriteLine( Math.Round(value, MidpointRounding.AwayFromZero) ); //out: -1
Console.WriteLine(Math.Round(value2, MidpointRounding.AwayFromZero)); //out: 1
Console.WriteLine(Math.Round(value3, MidpointRounding.ToEven)); //out: 1

答案 141 :(得分:10)

不确定这个是否已被提及,但ThreadStatic属性是一个非常有用的属性。这使静态字段仅为当前线程静态。

[ThreadStatic]
private static int _ThreadStaticInteger;

你不应该包含一个初始值设定项,因为它只对整个应用程序执行一次,你最好使该字段为空,并在使用它之前检查该值是否为空。

ASP.NET应用程序线程的另一个用途是重用,所以如果你修改它,它最终可能会用于另一个页面请求。

我仍然发现这有用几次。例如,在创建自定义事务类时:

using (DbTransaction tran = new DbTransaction())
{
    DoQuery("...");
    DoQuery("...");    
}

DbTransaction构造函数将ThreadStatic字段设置为self,并在dispose方法中将其重置为null。 DoQuery检查静态字段,如果!= null使用当前事务,否则默认为其他事务。我们避免将事务传递给每个方法,而且它可以很容易地包装其他方法,这些方法原本不是用于事务中的事务...

只需一次使用:)

答案 142 :(得分:10)

List<T>的TrueForAll方法:

List<int> s = new List<int> { 6, 1, 2 };

bool a = s.TrueForAll(p => p > 0);

答案 143 :(得分:10)

Or赋值运算符相当不错。你可以这样写:

x |= y

而不是:

x = x | y

如果你需要一个以x开头的变量或属性(false)但你想将它改为某个其他布尔变量/属性的值,这通常是实用的仅当其他值为true

答案 144 :(得分:10)

要调用基类构造函数,只需将base()与构造函数内联即可 要调用基类方法,只需将base.MethodName()放在派生类方法

class ClassA 
{
  public ClassA(int a)
  {
    //Do something
  }

  public void Method1()
  {
     //Do Something
  }
}

class ClassB : ClassA
{
  public ClassB(int a) : base(a) // calling the base class constructor
  {
    //Do something
  }

  public void Method2()
  {
    base.Method1();               // calling the base class method
  }
}

当然,只需说出base.MethodName()

即可调用基类的方法

答案 145 :(得分:10)

有很多人都知道的是一些C#引入的预处理程序指令。您可以使用#error This is an error.生成编译器错误并#warning This is a warning.

当我使用自上而下的方法开发“todo”列表时,我通常会使用这些。我会#error Implement this function#warning Eventually implement this corner case作为提醒。

答案 146 :(得分:9)

字符串实习。这是我尚未见过的讨论。它有点模糊,但在某些条件下它可能很有用。

CLR保留一个对文字字符串的引用表(以及以编程方式实现的字符串)。如果在代码中的多个位置使用相同的字符串,它将在表中存储一次。这可以减轻分配字符串所需的内存量。

您可以使用String.IsInterned(string)测试字符串是否被实习,并且您可以使用String.Intern(string)实习字符串。

注意: CLR可以在应用程序甚至AppDomain结束后保留​​对实习字符串的引用。有关详细信息,请参阅MSDN文档。

答案 147 :(得分:9)

System.Diagnostics.Debug.Assert (false);

将触发弹出窗口并允许您在执行期间将调试器附加到正在运行的.NET进程。对于那些由于某种原因你无法直接调试ASP.NET应用程序的时候非常有用。

答案 148 :(得分:9)

要使用LINQ测试IEnumerable <T>是否为空,请使用:

  

的IEnumerable <T>任何();

  • 起初我正在使用(IEnumerable <T>。Count()!= 0)...
    • 这会不必要地导致IEnumerable <T>中的所有项目都被枚举。
  • 作为对此的改进,我继续使用(IEnumerable <T>。FirstOrDefault()== null)...
    • 哪个更好......
  • 但IEnumerable <T>。Any()是最简洁的,表现最佳。

答案 149 :(得分:9)

使用枚举。

将字符串转换为枚举:

enum MyEnum
{
    FirstValue,
    SecondValue,
    ThirdValue
}

string enumValueString = "FirstValue";
MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), enumValueString, true)
  • 我使用它从数据库中的设置表中加载我的ASP.NET应用程序中的CacheItemPriority值,这样我就可以动态地控制缓存(以及其他设置),而无需关闭应用程序。

比较enum类型的变量时,不必转换为int:

MyEnum val = MyEnum.SecondValue;
if (val < MyEnum.ThirdValue)
{
    // Do something
}

答案 150 :(得分:9)

如果您希望在调试和释放模式之间采用不同的行为,那么预处理器指令可能很有用。

http://msdn.microsoft.com/en-us/library/ed8yd1ha.aspx

答案 151 :(得分:9)

我非常喜欢函数的隐式泛型参数。例如,如果您有:

public void DoStuff<T>(T value);

而不是这样称呼它:

DoStuff<int>(5);

你可以:

DoStuff(5);

它将从参数的类型中找出泛型类型。

  • 如果您通过反射调用该方法,则此方法无效。
  • 我记得Mono上有一些奇怪的问题。

答案 152 :(得分:9)

IEnumerable的{​​{1}},它将列表列表展平为单个列表。假设我有一个SelectMany列表,每个Orders都有一个Order列表。

我想知道LineItems已售出的总数...

LineItems

答案 153 :(得分:8)

字典初始值设定项对于需要对某些数据进行硬编码的快速黑客攻击和单元测试始终有用。

var dict = new Dictionary<int, string> { { 10, "Hello" }, { 20, "World" } };

答案 154 :(得分:8)

我很确定每个人都熟悉运算符重载,但也许有些人不熟悉。

class myClass
{
    private string myClassValue = "";

    public myClass(string myString)
    {
        myClassValue = myString;
    }

    public override string ToString()
    {
        return myClassValue;
    }

    public static myClass operator <<(myClass mc, int shiftLen)
    {
        string newString = "";
        for (int i = shiftLen; i < mc.myClassValue.Length; i++)
            newString += mc.myClassValue[i].ToString();
        mc.myClassValue = newString.ToString();
        return mc;
    }

    public static myClass operator >>(myClass mc, int shiftLen)
    {
        char[] newString = new char[shiftLen + mc.myClassValue.Length];

        for (int i = shiftLen; i < mc.myClassValue.Length; i++)
            newString[i] += mc.myClassValue[i - shiftLen];

        mc.myClassValue = new string(newString);
        return mc;
    }

    public static myClass operator +(myClass mc, string args)
    {
        if (args.Trim().Length > 1)
            mc.myClassValue += args;
        return mc;
    }

    public static myClass operator -(myClass mc, string args)
    {
        if (args.Trim().Length > 1)
        {
            Regex rgx = new Regex(args);
            mc.myClassValue = rgx.Replace(mc.myClassValue, "");
        }
        return mc;
    }
}

我认为能够使用&lt;&lt;左右移动字符串非常酷。和&gt;&gt;或者使用 - =

删除一组遵循正则表达式模式的字符串
myClass tmpClass = new myClass("  HelloWorld123");
tmpClass -= @"World";
tmpClass <<= 2;
Console.WriteLine(tmpClass);

答案 155 :(得分:8)

你可以打开字符串!

switch(name)
{
  case "Dave":
    return true;
  case "Bob":
    return false;
  default:
    throw new ApplicationException();
}

非常方便!并且比一堆if-else语句更清洁

答案 156 :(得分:8)

在C#3.5中初始化字典的表达式:

new Dictionary<string, Int64>() {{"Testing", 123}, {"Test", 125}};

答案 157 :(得分:8)

使用LINQ,可以根据参数创建新功能。 如果你有一个很常见的微小函数,这是非常好的,但参数需要一些时间来计算。

    public Func<int> RandomGenerator
    {
        get
        {
            var r = new Random();
            return () => { return r.Next(); };
        }
    }

    void SomeFunction()
    {
        var result1 = RandomGenerator();

        var x = RandomGenerator;
        var result2 = x();
    }

答案 158 :(得分:8)

不是C#特定的东西,但我是三元手术迷。

而不是

if (boolean Condition)
{
    //Do Function
}
else
{
    //Do something else
}

你可以使用简洁

booleanCondtion ? true operation : false operation;

e.g。

而不是

int value = param;
if (doubleValue)
{
    value *= 2;
}
else
{
    value *= 3;
}

你可以输入

int value = param * (tripleValue ? 3 : 2);

它确实有助于编写简洁的代码,但是嵌套该死的东西可能是令人讨厌的,它们可以用于邪恶,但我仍然喜欢小吸盘

答案 159 :(得分:8)

而不是做这样的俗气:

Console.WriteLine("{0} item(s) found.", count);

我使用以下内联技巧:

Console.WriteLine("{0} item{1} found.", count, count==1 ? "" : "s");

当有一个项目或“项目”时,如果有更多(或更少)的项目,则会显示“项目”。为了一点专业性,不会付出太多努力。

答案 160 :(得分:8)

C#允许您将属性设置器方法添加到实现只读接口属性的具体类型,即使接口声明本身没有属性设置器也是如此。例如:

public interface IReadOnlyFoo
{
   object SomeReadOnlyProperty { get; }
}

具体类看起来像这样:

internal class Foo : IReadOnlyFoo
{
   public object SomeReadOnlyProperty { get; internal set; }
}

有趣的是,如果将它转换为IReadOnlyFoo接口,Foo类是不可变的:

// Create a Foo instance
Foo foo = new Foo();

// This statement is legal
foo.SomeReadOnlyProperty = 12345;

// Make Foo read only
IReadOnlyFoo readOnlyFoo = foo;

// This statement won't compile
readOnlyFoo.SomeReadOnlyProperty = 54321;

答案 161 :(得分:7)

我正在通过“Pro ASP.NET MVC框架”(APress)这本书阅读并观察了作者正在使用对我来说很陌生的Dictionary对象。

他在不使用Add()方法的情况下添加了新的键/值对。然后他覆盖相同的键/值对,而不必检查该键是否已存在。例如:

Dictionary<string, int> nameAgeDict = new Dictionary<string, int>();
nameAgeDict["Joe"] = 34;      // no error. will just auto-add key/value
nameAgeDict["Joe"] = 41;      // no error. key/value just get overwritten
nameAgeDict.Add("Joe", 30);   // ERROR! key already exists

在很多情况下,我不需要检查我的词典是否已经有一个键,我只想添加相应的键/值对(如果需要,覆盖现有的键/值对。)对于这个发现,我总是要在添加之前检查密钥是否已经存在。

答案 162 :(得分:7)

关于foreach:它不使用'duck typing',因为鸭子输入IMO是指运行时检查。它在编译时使用结构类型检查(而不是名义上的)来检查类型中所需的方法。

答案 163 :(得分:7)

在通用代码中使用default关键字来返回类型的默认值。

public class GenericList<T>
{
    private class Node
    {
        //...

        public Node Next;
        public T Data;
    }

    private Node head;

    //...

    public T GetNext()
    {
        T temp = default(T);

        Node current = head;
        if (current != null)
        {
            temp = current.Data;
            current = current.Next;
        }
        return temp;
    }
}

Another example here

答案 164 :(得分:7)

HttpContext.Current.Server.Execute 

非常适合将HTML呈现为AJAX回调的字符串。您可以将其与组件一起使用,而不是拼凑HTML字符串片段。我能够将页面臃肿减少几百KB,几乎没有任何混乱。我这样用过:

Page pageHolder = new Page();
UserControl viewControl = (UserControl)pageHolder.LoadControl(@"MyComponent.ascx");
pageHolder.Controls.Add(viewControl);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();

答案 165 :(得分:7)

Eric Lippert的

Four switch oddities

答案 166 :(得分:7)

我不认为有人提到追加?在值类型名称之后将使其可为空。

你可以这样做:

DateTime? date = null;

DateTime是一个结构。

答案 167 :(得分:7)

当您想要Invoke / BeginInvoke内联代码时,内置(2.0)MethodInvoker委托很有用。这避免了需要创建实际的委托和单独的方法。

    void FileMessageEvent(object sender, MessageEventArgs e)
    {

        if (this.InvokeRequired == true)
        {
            this.BeginInvoke((MethodInvoker)delegate { 
                     lblMessage.Text=e.Message; 
                     Application.DoEvents(); 
                 }
            ); 

        }
    }

解决错误:“无法将匿名方法转换为'System.Delegate'类型,因为它不是委托类型”。

答案 168 :(得分:7)

使用lambdas时模拟功能性“通配符”参数(如Haskell中的“_”)的酷技巧:

(_, b, __) => b.DoStuff();  // only interested in b here

答案 169 :(得分:7)

数组初始化而不指定数组元素类型:

var pets = new[] { "Cat", "Dog", "Bird" };

答案 170 :(得分:7)

不确定是否提及过这个(11页!!)

但是当您对要序列化的类/对象进行版本化时,类的OptionalField属性是惊人的。

http://msdn.microsoft.com/en-us/library/ms229752(VS.80).aspx

答案 171 :(得分:7)

除了duncansmart的回复之外,还可以在Framework 2.0上使用扩展方法。只需在System.Runtime.CompilerServices命名空间下添加一个ExtensionAttribute类,您就可以使用扩展方法(当然只能使用C#3.0)。

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute
    { 
    }
}

答案 172 :(得分:7)

Object.ReferenceEquals方法

确定指定的Object实例是否是同一个实例。

<强>参数:

  • objA:System.Object - 要比较的第一个Object。
  • objB:System.Object - 要比较的第二个Object。

示例:

 object o = null;
 object p = null;
 object q = new Object();

 Console.WriteLine(Object.ReferenceEquals(o, p));
 p = q;
 Console.WriteLine(Object.ReferenceEquals(p, q));
 Console.WriteLine(Object.ReferenceEquals(o, p));

与“==”和“.Equals”的区别:

基本上,对象A的Equals()测试与对象B具有相同的内容。

方法System.Object.ReferenceEquals()始终比较引用。 虽然类可以为相等运算符提供自己的行为 (如下所示),如果调用运算符,则不会调用重定义的运算符 通过对System.Object的引用。

对于字符串,没有什么区别,因为已经重写了==和Equals来比较字符串的内容。

另见this answer另一个问题(“如何在没有无限递归的情况下检查'=='运算符重载中的空值?”)。

答案 173 :(得分:7)

查看组件时要显示的属性设计视图中的属性:

private double _Zoom = 1;

[Category("View")]
[Description("The Current Zoom Level")]
public double Zoom
{
get { return _Zoom;}
set { _Zoom = value;}
}

使组件库的其他用户更轻松。

答案 174 :(得分:7)

[field: NonSerialized]
public event EventHandler Event;

这样,事件监听器就不会被序列化。

仅[NonSerialized]不起作用,因为NonSerializedAttribute只能应用于字段。

答案 175 :(得分:7)

这是我最近发现的一个有用的东西:

Microsoft.VisualBasic.Logging.FileLogTraceListener

MSDN Link

这是一个TraceListener实现,它具有很多功能,例如自动日志文件翻转,我以前会使用自定义日志记录框架。好处是它是.NET的核心部分,并与Trace框架集成,因此易于立即使用和使用。

这是“隐藏”的,因为它在Microsoft.VisualBasic程序集中......但你也可以在C#中使用它。

答案 176 :(得分:7)

我喜欢

#if DEBUG
           //Code run in debugging mode

#else
           //Code run in release mode

#endif

答案 177 :(得分:7)

Explicit interface member implementation,其中实现了接口成员,但除非将实例强制转换为接口类型,否则将隐藏。

答案 178 :(得分:7)

您可以在非泛型类中使用泛型方法。

答案 179 :(得分:7)

您输入“prop”,然后按[TAB]两次,它会为您的属性生成有用的代码,并可以加快您的输入速度。

我知道这可以在VS 2005中使用(我使用它),但我不知道以前的版本。

答案 180 :(得分:7)

使用LINQ对过去采用迭代和条件的集合进行内联工作的能力非常有价值。值得了解所有LINQ扩展方法如何帮助您的代码更加紧凑和可维护。

答案 181 :(得分:7)

这不是C#特定类型,但我刚刚找到了ISurrogateSelector和ISerializationSurrogate接口 -

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.isurrogateselector.aspx

http://msdn.microsoft.com/en-us/library/system.runtime.serialization.isurrogateselector.aspx

将这些与BinaryFormatter结合使用,可以通过实现代理类来序列化非序列化对象。代理模式在计算机科学中是很好理解的,特别是在处理序列化问题时。我认为这个实现只是隐藏为BinaryFormatter的构造函数的参数,而且太糟糕了。

仍然 - 非常隐藏。 :)

答案 182 :(得分:7)

您可以使用扩展方法创建委托,就像它们是常规方法一样,可以使用this参数。例如,

static class FunnyExtension {
    public static string Double(this string str) { return str + str; }
    public static int Double(this int num) { return num + num; }
}


Func<string> aaMaker = "a".Double;
Func<string, string> doubler = FunnyExtension.Double;

Console.WriteLine(aaMaker());       //Prints "aa"
Console.WriteLine(doubler("b"));    //Prints "bb"

请注意,这不适用于扩展的扩展方法 值类型;见this question

答案 183 :(得分:7)

C#4.0中的动态关键字

如果希望仅在运行时解析方法调用,则可以使用dynamic关键字。

dynamic invoker=new DynamicInvoker();
dynamic result1=invoker.MyMethod1();
dynamic result2=invoker.MyMethod2();

这里我正在实施一个动态调用者。

public class DynamicInvoker : IDynamicObject
    {
        public MetaObject GetMetaObject
              (System.Linq.Expressions.Expression parameter)
        {
            return new DynamicReaderDispatch (parameter);
        }
    }

    public class DynamicDispatcher : MetaObject
    {
        public DynamicDispatcher (Expression parameter) 
                   : base(parameter, Restrictions.Empty){ }

        public override MetaObject Call(CallAction action, MetaObject[] args)
        {
            //You'll get MyMethod1 and MyMethod2 here (and what ever you call)
            Console.WriteLine("Logic to invoke Method '{0}'", action.Name);
            return this; //Return a meta object
        }
    }

答案 184 :(得分:7)

高级调试

显示

已提到的属性DebuggerDisplay和DebuggerBrowsable控制元素的可见性和显示的文本值。简单地重写ToString()将导致调试器使用该方法的输出。

如果您想要更复杂的输出,可以使用/创建Debugger Visualizer几个示例 有here

罢工之子

Microsoft提供称为SOS的调试器扩展。这是一个非常强大(虽然经常令人困惑)的扩展,这是诊断“泄漏”的一种很好的方法,更准确地说是对不再需要的对象的不必要的引用。

框架源的符号服务器

遵循这些instructions将允许您逐步完成框架某些部分的来源。

2010年的变化

Visual Studio 2010中存在一些增强功能和新功能:

答案 185 :(得分:6)

这意味着T必须具有公共无参数构造函数:

 class MyClass<T> where T : new()
 {

 }

答案 186 :(得分:6)

文字可以用作该类型的变量。 例如

Console.WriteLine(5.ToString());
Console.WriteLine(5M.GetType());   // Returns "System.Decimal"
Console.WriteLine("This is a string!!!".Replace("!!", "!"));

只是一点点琐事......

人们没有提到过很多东西,但它们主要与不安全的构造有关。以下是“常规”代码可以使用的代码:

已选中/未选中的关键字:

public static int UncheckedAddition(int a, int b)
{
    unchecked { return a + b; }
}

public static int CheckedAddition(int a, int b)
{
    checked { return a + b; } // or "return checked(a + b)";
}

public static void Main() 
{
    Console.WriteLine("Unchecked: " + UncheckedAddition(Int32.MaxValue, + 1));  // "Wraps around"
    Console.WriteLine("Checked: " + CheckedAddition(Int32.MaxValue, + 1));  // Throws an Overflow exception
    Console.ReadLine();
}

答案 187 :(得分:6)

阅读有关.NET框架开发的书。一个很好的建议是不要使用bool打开或关闭内容,而是使用ENums。

使用ENums,您可以为自己提供一些可扩展性,而无需重写任何代码来为函数添加新功能。

答案 188 :(得分:6)

Mixins是一个不错的功能。基本上,mixins让你有一个接口而不是类的具体代码。然后,只需在一堆类中实现该接口,您就可以自动获得mixin功能。例如,要将深度复制混合到多个类中,请定义接口

internal interface IPrototype<T> { }

为此界面添加功能

internal static class Prototype
{
  public static T DeepCopy<T>(this IPrototype<T> target)
  {
    T copy;
    using (var stream = new MemoryStream())
    {
      var formatter = new BinaryFormatter();
      formatter.Serialize(stream, (T)target);
      stream.Seek(0, SeekOrigin.Begin);
      copy = (T) formatter.Deserialize(stream);
      stream.Close();
    }
    return copy;
  }
}

然后实现任何类型的接口以获得mixin。

答案 189 :(得分:6)

我不喜欢使用int.TryParse()或Convert.ToInt32(),而是使用静态整数解析函数,当它无法解析时返回null。然后我可以用??和三元运算符一起更清楚地确保我的声明和初始化都以易于理解的方式在一行上完成。

public static class Parser {
    public static int? ParseInt(string s) {
        int result;
        bool parsed = int.TryParse(s, out result);
        if (parsed) return result;
        else return null;
    }
    // ...
}

这也有助于避免重复赋值的左侧,但更好的是避免在赋值的右侧重复长调用,例如以下示例中的数据库调用。而不是丑陋的if-then树(我经常遇到):

int x = 0;
YourDatabaseResultSet data = new YourDatabaseResultSet();
if (cond1)
    if (int.TryParse(x_input, x)){
        data = YourDatabaseAccessMethod("my_proc_name", 2, x);
    }
    else{
        x = -1;
        // do something to report "Can't Parse"    
    }
}
else {
    x = y;
    data = YourDatabaseAccessMethod("my_proc_name", 
       new SqlParameter("@param1", 2),
       new SqlParameter("@param2", x));
}

你可以这样做:

int x = cond1 ? (Parser.ParseInt(x_input) ?? -1) : y;
if (x >= 0)  data = YourDatabaseAccessMethod("my_proc_name", 
    new SqlParameter("@param1", 2),
    new SqlParameter("@param2", x));

更清洁,更容易理解

答案 190 :(得分:6)

我特别喜欢可以为空的DateTime。因此,如果你有一些日期给出的情况和其他没有给出日期的情况,我认为最好使用和恕我直言,使用DateTime.MinValue或其他任何东西更容易理解......

DateTime? myDate = null;

if (myDate.HasValue)
{
    //doSomething
}
else
{
    //soSomethingElse
}

答案 191 :(得分:6)

可以为枚举定义数据类型:

enum EnumName : [byte, char, int16, int32, int64, uint16, uint32, uint64]
{
    A = 1,
    B = 2
}

答案 192 :(得分:6)

阅读了所有9页后,我觉得我必须指出一些未知的特征......

这适用于.NET 1.1,在gzip压缩文件上使用压缩/解压缩,其中一个必须:

  • 下载ICSharpCode.ZipLib
  • 或者,将Java库引用到您的项目中,并使用Java的内置库来利用GZip的压缩/解压缩方法。

它未充分利用,我还不知道,(仍然使用ICSharpCode.ZipLib,即使使用.NET 2 / 3.5)是它在System.IO.Compression中被合并到标准BCL版本2中命名空间...请参阅MSDN页面“GZipStream Class”。

答案 193 :(得分:6)

C#中的指针。

它们可用于执行就地字符串操作。这是一个不安全的功能,因此unsafe关键字用于标记不安全代码的区域。另请注意固定关键字如何用于指示指向的内存是固定的,并且不能由GC移动。这是指向内存地址的指针,GC必须将内存移动到不同的地址,否则会导致指针无效。

    string str = "some string";
    Console.WriteLine(str);
    unsafe
    {
        fixed(char *s = str)
        {
            char *c = s;
            while(*c != '\0')
            {
                *c = Char.ToUpper(*c++);                    
            }
        }
    }
    Console.WriteLine(str);

我不会这样做,只是为了这个问题来展示这个功能。

答案 194 :(得分:6)

(我刚用过这个)将字段设置为null并返回它而没有中间变量:

try
{
    return _field;
}
finally
{
    _field = null;
}

答案 195 :(得分:6)

@Brad Barker

我认为如果你必须使用可空类型,最好使用Nullable&lt; .T&gt;而不是问号符号。令人惊讶的是,魔法正在发生。 不知道为什么有人会想要使用Nullable&lt; .bool&gt;虽然。 : - )

Krzysztof Cwalina(Framwork Design Guidlines的作者之一)在这里发表了一篇好文章: http://blogs.msdn.com/kcwalina/archive/2008/07/16/Nullable.aspx

Mike Hadlow在Nullability Voodoo

上发表了一篇不错的帖子

答案 196 :(得分:6)

开放式泛型是另一个方便的功能,尤其是在使用Inversion of Control时:

container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>));

答案 197 :(得分:6)

我无法弄清楚Convert类中的某些函数有什么用(例如Convert.ToDouble(int),Convert.ToInt(double)),直到我将它们与{{1}组合在一起}:

Array.ConvertAll

这避免了因定义内联委托/闭包而产生的资源分配问题(并且稍微更具可读性):

int[] someArrayYouHaveAsInt;
double[] copyOfArrayAsDouble = Array.ConvertAll<int, double>(
                                someArrayYouHaveAsInt,
                                new Converter<int,double>(Convert.ToDouble));

答案 198 :(得分:6)

我对这个问题这么迟,但是我想补充一些我认为没有涵盖的问题。这些不是C#特定的,但我认为对于任何C#开发人员来说都值得一提。

AmbientValueAttribute

这与DefaultValueAttribute类似,但它不提供属性默认的值,而是提供属性用于决定是否从其他位置请求其值的值。例如,对于WinForms中的许多控件,他们的ForeColorBackColor属性都有AmbientValue Color.Empty,因此他们知道从父控件获取颜色。

IsolatedStorageSettings

这是一个Silverlight。该框架轻松地包含了这个密封类,用于在每个应用程序和每个站点级别提供设置持久性。

标记与扩展方法的交互

使用扩展方法,标记枚举的使用可以更具可读性。

    public static bool Contains(
          this MyEnumType enumValue,
          MyEnumType flagValue)
    {
        return ((enumValue & flagValue) == flagValue);
    }

    public static bool ContainsAny(
          this MyEnumType enumValue,
          MyEnumType flagValue)
    {
        return ((enumValue & flagValue) > 0);
    }

这使得检查标志值很好并且易于读写。当然,如果我们可以使用泛型并强制使用T作为枚举会更好,但这是不允许的。也许dynamic会使这更容易。

答案 199 :(得分:6)

我发现令人难以置信的是,编译器使用外部变量编写了什么样的麻烦:

string output = "helo world!";
Action action = () => Console.WriteLine(output);
output = "hello!";
action();

这实际上会打印hello!。为什么?因为编译器为委托创建了一个嵌套类,所有外部变量的公共字段并在每次调用委托之前插入设置代码:)以上是代码'reflectored':

Action action;
<>c__DisplayClass1 CS$<>8__locals2;
CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.output = "helo world!";
action = new Action(CS$<>8__locals2.<Main>b__0);
CS$<>8__locals2.output = "hello!";
action();

我觉得很酷。

答案 200 :(得分:6)

从匿名方法访问局部变量允许您使用新的控制流逻辑包装任何代码,而不必将该代码分解为另一种方法。在方法外部声明的局部变量在方法中可用,例如此处示例中的endOfLineChar局部变量:

http://aaronls.wordpress.com/2010/02/02/retrying-on-exception-conditionally/

答案 201 :(得分:6)

Math.Max和Min检查边界: 我已经在很多代码中看到了这一点:

if (x < lowerBoundary) 
{
   x = lowerBoundary;
}

我觉得这个更小,更干净,更易读:

x = Math.Max(x, lowerBoundary);

或者您也可以使用三元运算符:

x = ( x < lowerBoundary) ? lowerBoundary : x;

答案 202 :(得分:6)

我称这个AutoDebug是因为您可以根据bool值直接进入调试,这也可以存储为项目用户设置。

示例:

//Place at top of your code
public UseAutoDebug = true;


//Place anywhere in your code including catch areas in try/catch blocks
Debug.Assert(!this.UseAutoDebug);

只需将上面的内容放在try / catch块或代码的其他区域中,并将UseAutoDebug设置为true或false,并在您希望进行测试时随时进入调试。

您可以保留此代码并在测试时打开和关闭此功能,您也可以将其保存为项目设置,并在部署后手动更改它以在需要时从用户处获取其他错误信息。

您可以在此Visual Studio C#项目模板中看到使用此技术的功能和实际示例,其中大量使用它:

http://code.msdn.microsoft.com/SEHE

答案 203 :(得分:6)

刚刚学习了不变性,协方差和逆变的意义后,我发现了将包含在.NET 4.0中的inout泛型修饰符。它们似乎模糊不清,大多数程序员都不会知道它们。

Visual Studio Magazine上有一个article,它讨论了这些关键字及其使用方法。

答案 204 :(得分:6)

没有特别的顺序:

Lists<>
Mutex

Framework 3.5中的新属性定义快捷方式。

答案 205 :(得分:6)

这不是C#特有的功能,但它是一个我发现非常有用的插件。它被称为资源重构工具。它允许您右键单击文字字符串并将其提取到资源文件中。它将搜索代码并找到匹配的任何其他文字字符串,并将其替换为Resx文件中的相同资源。

http://www.codeplex.com/ResourceRefactoring

答案 206 :(得分:6)

新修饰符

C#中“new”修饰符的使用并未完全隐藏,但并不常见。当您需要“隐藏”基类成员而不是总是覆盖它们时,new修饰符会派上用场。这意味着当您将派生类转换为基类时,“隐藏”方法变为可见,并且在派生类中调用而不是相同的方法。

在代码中更容易看到:

public class BaseFoo
{
    virtual public void DoSomething()
    {
        Console.WriteLine("Foo");
    }
}

public class DerivedFoo : BaseFoo
{
    public new void DoSomething()
    {
        Console.WriteLine("Bar");
    }
}

public class DerivedBar : BaseFoo
{
    public override void DoSomething()
    {
        Console.WriteLine("FooBar");
    }
}

class Program
{
    static void Main(string[] args)
    {
        BaseFoo derivedBarAsBaseFoo = new DerivedBar();
        BaseFoo derivedFooAsBaseFoo = new DerivedFoo();

        DerivedFoo derivedFoo = new DerivedFoo();

        derivedFooAsBaseFoo.DoSomething(); //Prints "Foo" when you might expect "Bar"
        derivedBarAsBaseFoo.DoSomething(); //Prints "FooBar"

        derivedFoo.DoSomething(); //Prints "Bar"
    }
}

[编辑:我为双关语获得额外积分吗?对不起,无法帮助。]

答案 207 :(得分:6)

方法组并不为人所知。

假设:

Func<Func<int,int>,int,int> myFunc1 = (i, j) => i(j);
Func<int, int> myFunc2 = i => i + 2;

你可以这样做:

var x = myFunc1(myFunc2, 1);

而不是:

var x = myFunc1(z => myFunc2(z), 1);

答案 208 :(得分:6)

Yield关键字在功能强大时经常被忽略。我前一段时间在博客上讨论了它并讨论了好处(不同的处理方式),并在收益率的引导下发生,以帮助提供更强的理解。

Using Yield in C#

答案 209 :(得分:6)

想到 @dp AnonCast 并决定尝试一下。以下是我提出的可能对某些人有用的内容:

// using the concepts of dp's AnonCast
static Func<T> TypeCurry<T>(Func<object> f, T type)
{
    return () => (T)f();
}

以下是它的使用方法:

static void Main(string[] args)
{

    var getRandomObjectX = TypeCurry(GetRandomObject,
        new { Name = default(string), Badges = default(int) });

    do {

        var obj = getRandomObjectX();

        Console.WriteLine("Name : {0} Badges : {1}",
            obj.Name,
            obj.Badges);

    } while (Console.ReadKey().Key != ConsoleKey.Escape);

}

static Random r = new Random();
static object GetRandomObject()
{
    return new {
        Name = Guid.NewGuid().ToString().Substring(0, 4),
        Badges = r.Next(0, 100)
    };
}

答案 210 :(得分:6)

我发现在Visual Studio中使用条件中断函数非常有用。我喜欢它允许我将值设置为某些东西的方式,例如,只有在极少数情况下才能满足,并且从那里我可以进一步检查代码。

答案 211 :(得分:5)

Action和Func将帮助器与lambda方法一起委托。我将这些用于需要委托以提高可读性的简单模式。例如,一个简单的缓存模式是检查缓存中是否存在请求的对象。如果确实存在:返回缓存的对象。如果它不存在,则生成新实例,缓存新实例并返回新实例。相反,我可以从缓存中存储/检索的每个对象写入此代码1000次,我可以编写一个简单的模式方法,如此...

private static T CachePattern<T>(string key, Func<T> create) where T : class
{
    if (cache[key] == null)
    {
        cache.Add(key, create());
    }

    return cache[key] as T;
}

...然后我可以通过在自定义缓存管理器中使用以下内容来大大简化缓存获取/设置代码

public static IUser CurrentUser
{
    get
    {
        return CachePattern<IUser>("CurrentUserKey", () => repository.NewUpUser());
    }
}

现在,简单的“日常”代码模式可以编写一次,并且可以更轻松地重复使用恕我直言。我不必编写委托类型并弄清楚我想如何实现回调等。如果我能在10秒内写出来,那我就不那么贴切了。无论是懒惰的初始化还是上面显示的其他一些例子,都可以使用简单的代码模式:

答案 212 :(得分:5)

我在使用linqxml时发现这项技术很有趣:

public bool GetFooSetting(XElement ndef){
   return (bool?)ndef.Element("MyBoolSettingValue") ?? true;
}

而不是:

public bool GetFooSetting(XElement ndef){
   return ndef.Element("MyBoolSettingValue") != null ? bool.Parse(ndef.Element("MyBoolSettingValue") ) : true;
}

答案 213 :(得分:5)

我没有发现 - 近一年 - 强类型DataRows包含一个Is [ColumnName] Null()方法。

例如:

Units.UnitsDataTable dataTable = new Units.UnitsDataTable();

foreach (Units.UnitsRow row in dataTable.Rows)
{
    if (row.IsPrimaryKeyNull())
        //....

    if (row.IsForeignKeyNull())
        //....
}

答案 214 :(得分:5)

构造链是否已被引用?

namespace constructorChain {
    using System;

    public class Class1 {
        public string x;
        public string y;

        public Class1() {
            x = "class1";
            y = "";
        }

        public Class1(string y)
            : this() {
            this.y = y;
        }
    }

    public class Class2 : Class1 {
        public Class2(int y)
            : base(y.ToString()) {

        }
    }
}

...

        constructorChain.Class1 c1 = new constructorChain.Class1();
        constructorChain.Class1 c12 = new constructorChain.Class1("Hello, Constructor!");
        constructorChain.Class2 c2 = new constructorChain.Class2(10);
        Console.WriteLine("{0}:{1}", c1.x, c1.y);
        Console.WriteLine("{0}:{1}", c12.x, c12.y);
        Console.WriteLine("{0}:{1}", c2.x, c2.y);

        Console.ReadLine();

答案 215 :(得分:5)

我喜欢EditorBrowsableAttribute。它允许您控制是否在Intellisense中显示方法/属性。您可以将值设置为“始终”,“高级”或“从不”。

From MSDN ...

<强>说明

EditorBrowsableAttribute是设计者的提示,指示是否要显示属性或方法。您可以在可视化设计器或文本编辑器中使用此类型来确定用户可见的内容。例如,Visual Studio中的IntelliSense引擎使用此属性来确定是否显示属性或方法。

在Visual C#中,您可以控制何时在“智能感知”和“属性”窗口中显示高级属性,并使用“工具”|“隐藏高级成员”设置。选项|文字编辑器| C#。相应的EditorBrowsableState为Advanced。

答案 216 :(得分:5)

Nullable.GetValueOrDefault?

答案 217 :(得分:5)

如果提到这个,我道歉,但我经常使用它。

Visual Studio的加载项由Alex Papadimoulis开发。它用于将常规文本粘贴为字符串,字符串构建器,注释或区域。

http://weblogs.asp.net/alex_papadimoulis/archive/2004/05/25/Smart-Paster-1.1-Add-In---StringBuilder-and-Better-C_2300_-Handling.aspx

在这个插件中(我也不知道是否已经提到过)我注意到字符串是用字符串文字前缀粘贴的:

@

我知道这些,但我不知道在文字中使用双引号来逃避引用。

例如

string s = "A line of text" + Environment.NewLine + "Another with a \"quote\"!!";

可以表示为

string s = @"A line of text 
Another with a ""quote""!!";

答案 218 :(得分:5)

System.Runtime.Remoting.Proxies.RealProxy

它可以在C#中实现面向方面编程,你也可以用它来做很多其他的花哨的东西。

答案 219 :(得分:5)

__ arglist也是

[DllImport("msvcrt40.dll")]
public static extern int printf(string format, __arglist);

static void Main(string[] args)
{
   printf("Hello %s!\n", __arglist("Bart"));
}

答案 220 :(得分:5)

我喜欢使用 using 指令重命名一些类,以便于阅读:

// defines a descriptive name for a complexed data type
using MyDomainClassList = System.Collections.Generic.List<
  MyProjectNameSpace.MyDomainClass>;

....


MyDomainClassList myList = new MyDomainClassList();
/* instead of 
List<MyDomainClass> myList = new List<MyDomainClass>();
*/

这对于代码维护也非常方便。如果您需要更改类名,则只需要更改一个位置。另一个例子:

using FloatValue  = float; // you only need to change it once to decimal, double...

....
FloatValue val1;
...

答案 221 :(得分:5)

我刚刚学到的一个问题是你仍然可以拨打methods on a nullable value ....

当你有一个可以为空的值时,结果是什么:

decimal? MyValue = null;

你可能认为你必须写:

MyValue == null ? null : MyValue .ToString()

你可以写:

MyValue.ToString()

我已经知道我可以调用MyValue.HasValue和MyValue.Value ......但它没有完全点击我可以调用ToString()。

答案 222 :(得分:5)

反思Emit和表达树浮现在脑海中......

不要错过Jeffrey Richter的CLR,通过C#和Jon Skeet的alt text

请参阅此处了解一些资源:

http://www.codeproject.com/KB/trace/releasemodebreakpoint.aspx

http://www.codeproject.com/KB/dotnet/Creating_Dynamic_Types.aspx

http://www.codeproject.com/KB/cs/lambdaexpressions.aspx

答案 223 :(得分:5)

我没有看到这个:

for (;;);

相同
while (true) ;

答案 224 :(得分:5)

通用事件处理程序:

public event EventHandler<MyEventArgs> MyEvent;

这样您就不必一直声明自己的代表,

答案 225 :(得分:5)

这不会编译:

namespace ns
{
    class Class1
    {
        Nullable<int> a;
    }
}

找不到类型或命名空间名称'Nullable'(您是否缺少using指令或程序集引用?)&lt; - missing using System;'

但是

namespace ns
{
    class Class1
    {
        int? a;
    }
}

会编译! (.NET 2.0)。

答案 226 :(得分:5)

零参数Lambdas

()=>Console.ReadLine()

答案 227 :(得分:5)

@lainMH,

当从可以为空的数据库中检索值并将值重新放入时,可以为空的布尔值非常有用。有时您想知道该字段尚未设置。

答案 228 :(得分:5)

允许使用带括号的空块。

你可以写这样的代码

{
    service.DoTonsOfWork(args);
}

如果您想尝试没有usingtry... finally已经写过的内容,这会很有帮助。

//using(var scope = new TransactionScope)
{
    service.DoTonsOfWork(args);
}

答案 229 :(得分:5)

  

FIXED / C#中指针的强大功能 - 这个话题太大了,但我只想简单介绍一下。

在C中,我们有像......一样的加载结构的设施。

struct cType{
   char type[4];
   int  size;
   char name[50];
   char email[100];
}

cType myType;
fread(file, &mType, sizeof(mType));

我们可以在“unsafe”方法中使用fixed关键字来读取字节数组对齐的结构。

[Layout(LayoutKind.Sequential, Pack=1)]
public unsafe class CType{
    public fixed byte type[4];
    public int size;
    public fixed byte name[50];
    public fixed byte email[100];
}

方法1(从常规流读取到字节缓冲区并将字节数组映射到struct的各个字节)

CType mType = new CType();
byte[] buffer = new byte[Marshal.SizeOf(CType)];
stream.Read(buffer,0,buffer.Length);
// you can map your buffer back to your struct...
fixed(CType* sp = &mType)
{
    byte* bsp = (byte*) sp;
    fixed(byte* bp = &buffer)
    {
         for(int i=0;i<buffer.Length;i++)
         {
             (*bsp) = (*bp);
             bsp++;bp++;
         }
    }
}

方法2,您可以将Win32 User32.dll的ReadFile映射到直接读取字节...

CType mType = new CType();
fixed(CType* p = &mType)
{
    User32.ReadFile(fileHandle, (byte*) p, Marshal.SizeOf(mType),0);
}

答案 230 :(得分:4)

#region {string} 和#endregion对非常简洁,可用于分组代码(概述)。

#region Using statements
using System;
using System.IO;
using ....;
using ....;
#endregion

可以将代码块压缩为单个描述文本行。在函数内部工作。

答案 231 :(得分:4)

我喜欢滥用静态模板类不共享其静态成员的事实。

在编译时知道Dictionary<Type,...>实例时,这是一个线程安全(在创建时)和任何Type的廉价替代。

public static class MyCachedData<T>{
    static readonly CachedData Value;
    static MyCachedData(){
       Value=// Heavy computation, such as baking IL code or doing lots of reflection on a type
    }
}

干杯, 弗洛里安

答案 232 :(得分:4)

我在这次谈话中有点迟,我想提供以下内容。对于一些开发者来说,这可能是一件新事。

public class User
{
    public long UserId { get; set; }
    public String Name { get; set; }
    public String Password { get; set; }
    public String Email { get; set; }
}

声明和初始化它的常用方法是使用构造函数或类似跟随。

User user = new User();
user.UserId = 1;
user.Name = "myname";
etc

但我学会了如何初始化它。我知道Visual Basic开发人员会喜欢它,因为它就像只有VB.NET中的操作符,而不是C#中的操作符,如下所示。

User user = new User()
{
    UserId = 1,
    Name = "myname",
    Email = "myemail@domain.com",
    Password = "mypassword"
};

答案 233 :(得分:4)

通用约束:

 //Constructor constraint, T has a default empty constructor
class Node<K,T> where T : new() 
{
}

//Reference\Value Type constraints
//T is a struct
public class MyClass<T> where T : struct 

{...}

//T is a reference type
public class MyClass<T> where T : class 

{...}

public class MyClass<T> where T : SomeBaseClass, ISomeInterface 

{...}

答案 234 :(得分:4)

我学到的一件有趣的事情是框架和C#语言的不同部分是在不同时间编写的,因此不一致。例如,框架本身违反了许多FxCop规则,因为在编写框架时规则并非全部到位。

此外,using语句用于对“范围”进行删除,而不是专门用于处理资源。它是在锁定声明之后写的。 Eric Gunnerson once mentioned如果使用using语句,他们可能不需要编写lock语句(虽然谁知道,也许他们会反正),因为using语句可能已经足够了

答案 235 :(得分:4)

您可以组合protectedinternal访问器,使其在同一个程序集中公开,但在不同的程序集中受到保护。这可以用于字段,属性,方法甚至常量。

答案 236 :(得分:4)

the standard已经解释了很多这方面的内容。这对于任何初学者和专家来说都是一本很好的阅读,这是很多阅读,但它是官方标准,而且它充满了多汁的细节。

一旦你完全理解了C#,就应该进一步了解Common Language Infrastructure的基本原理。 C#的架构和基础。

我遇到了各种程序员,他们不知道对象和ValueType之间的区别,除了它的附加限制。

熟悉这两个文件,你永远不会成为那个人。

答案 237 :(得分:4)

我不宽恕它,但我很惊讶goto仍在鸭子传入的射弹

答案 238 :(得分:4)

将枚​​举值转换为字符串值

鉴于枚举

enum Country
{
    UnitedKingdom, 
    UnitedStates,
    UnitedArabEmirates,
}

使用它:

public static void PrintEnumAsString( Country country )
{
    Console.Writeline( country.ToString() );
}

会将枚举值的名称打印为字符串,例如“UnitedKingdom的”

答案 239 :(得分:4)

我只想提一下(因为其中有T:struct的操作)C#编译器之一就是那个

where T : Enum

不会编译。它抛出错误“Constraint不能是特殊类'System.Enum'”。

答案 240 :(得分:4)

泛型和Curiously-Recurring Template Pattern确实有助于一些静态方法/属性声明。

假设您正在构建类层次结构:

class Base
{
}

class Foo: Base
{
}

class Bar: Base
{
}

现在,您希望在类型上声明静态方法,这些方法应该采用相同类型的参数(或返回值)或相同类型的静态属性。例如,您想要:

class Base
{
    public static Base Get()
    {
        // Return a suitable Base.
    }
}

class Foo: Base
{
    public static Foo Get()
    {
        // Return a suitable Foo.
    }
}

class Bar: Base
{
    public static Bar Get()
    {
        // Return a suitable Bar.
    }
}

如果这些静态方法基本上都做同样的事情,那么你手上就有很多重复的代码。一种解决方案是在返回值上删除类型安全性,并始终返回类型Base。但是,如果您想要类型安全,那么解决方案是将Base声明为:

class Base<T> where T: Base<T>
{
    public static T Get<T>()
    {
        // Return a suitable T.
    }
}

FooBar

class Foo: Base<Foo>
{
}

class Bar: Base<Bar>
{
}

这样,他们就会自动获得静态方法的副本

这也可以将 Singleton 模式封装在基类中(我知道下面的代码不是线程安全的,只是为了证明一点):

public class Singleton<T> where T: Singleton<T>, new()
{
  public static T Instance { get; private set; }

  static Singleton<T>()
  {
    Instance = new T();
  }
}

我意识到这会迫使你在你的单例子类上有一个公共的无参数构造函数,但是在没有where T: protected new()构造的编译时没有办法避免这种情况。但是可以使用reflection在运行时调用子类的protected / private无参数构造函数来实现它。

答案 241 :(得分:4)

我的一些人 - 按照你的意愿制作他们。

属性:

[assembly::InternalsVisibleTo("SomeAssembly")]

允许您将内部方法/属性或数据从程序集中暴露给另一个名为“SomeAssembly”的程序集。所有受保护/私密的东西都是隐藏的。


静态构造函数(也称为“类型构造函数”)

public MyClass
{
  public static MyClass()
  {
     // type init goes here
  }
  ......
}  

关键字internal。在很多方面非常有用。

答案 242 :(得分:4)

这对数据库应用程序开发人员来说可能是非常基础的,但我花了一些时间才意识到null与DBNull.value不同。

如果要查看数据库记录中的值是否为空,则必须使用DBNull.value。

答案 243 :(得分:4)

营销事件为不可序列化:

[field:NonSerializable]
public event SomeDelegate SomeEvent;

答案 244 :(得分:4)

Visual Studio最有用的功能之一是“Make object id”。它生成一个id并“附加”到对象,所以无论你在哪里查看对象,你都会看到id(无论是什么线程)。

调试时右键单击变量工具提示,然后就可以了。 它也适用于watchched / autos / locals变量。

答案 245 :(得分:4)

验证用户输入时,每种基本类型的TryParse方法都很棒。

double doubleValue
if (!Double.TryParse(myDataRow("myColumn"), out doubleValue))
{
    // set validation error
}

答案 246 :(得分:4)

Object Initializer中的Collection Initializer:

MailMessage mail = new MailMessage {
   To = { new MailAddress("a@example.com"), new MailAddress("b@example.com") },
   Subject = "Password Recovery"
};

您可以在单个表达式中初始化整个树。

答案 247 :(得分:4)

如果Visual Studio工具栏中有搜索文本框,则可以键入“&gt; of Program.cs”以打开Program.cs文件

答案 248 :(得分:4)

框架功能

我不知道,但我对VisualStyleRenderer和整个System.Windows.Forms.VisualStyles-Namespace感到非常惊讶。非常酷!

答案 249 :(得分:4)

Expression Trees怎么样?它们是LINQ的核心,允许延迟执行:

取自David Hayden's blog

在C#3.0中,您可以使用lambda表达式按如下方式定义委托:

Func<int,int> f = x => x + 1;

此委托在您的应用程序中编译为可执行代码,可以这样调用:

var three = f(2); // 2 + 1

代码按预期工作。没什么好看的。

表达式树

使用System.Query.Expression:

将委托定义为表达式树时
Expression<Func<int,int>> expression = x => x + 1;

委托不再编译成可执行代码,而是编译为可以转换并编译成原始委托的数据。

要在应用程序中实际使用表示为表达式树的委托,您必须在应用程序中编译并调用它:

var originalDelegate = expression.Compile();

var three = originalDelegate.Invoke(2);

答案 250 :(得分:4)

刚刚学会了[UnmanagedFunctionPointerAttribute(CallingConvention.CDecl)]的乐趣,试图与没有__stdcall定义回调的非托管C ++函数库进行交互。

答案 251 :(得分:4)

这与静态构造函数有关。这是一种执行静态破坏的方法(即在程序退出时清理资源)。

首先下课:

class StaticDestructor
{
    /// <summary>
    /// The delegate that is invoked when the destructor is called.
    /// </summary>
    public delegate void Handler();
    private Handler doDestroy;

    /// <summary>
    /// Creates a new static destructor with the specified delegate to handle the destruction.
    /// </summary>
    /// <param name="method">The delegate that will handle destruction.</param>
    public StaticDestructor(Handler method)
    {
        doDestroy = method;
    }

    ~StaticDestructor()
    {
        doDestroy();
    }
}

然后作为班级成员,你希望有一个“静态析构函数”:

private static readonly StaticDestructor destructor = new StaticDestructor
(
    delegate()
    {
        //Cleanup here
    }
);

现在将在最终垃圾收集时调用此方法。如果您绝对需要释放某些资源,这非常有用。

表现出这种行为的快速而肮脏的程序:

using System;

namespace TestStaticDestructor
{
    class StaticDestructor
    {
        public delegate void Handler();
        private Handler doDestroy;

        public StaticDestructor(Handler method)
        {
            doDestroy = method;
        }

        ~StaticDestructor()
        {
            doDestroy();
        }
    }

    class SomeClass
    {
        static SomeClass()
        {
            Console.WriteLine("Statically constructed!");
        }

        static readonly StaticDestructor destructor = new StaticDestructor(
            delegate()
            {
                Console.WriteLine("Statically destructed!");
            }
        );
    }

    class Program
    {
        static void Main(string[] args)
        {
            SomeClass someClass = new SomeClass();
            someClass = null;
            System.Threading.Thread.Sleep(1000);
        }
    }
}

当程序退出时,将调用“静态析构函数”。

答案 252 :(得分:4)

能够根据像

这样的通用参数创建类型的实例

new T();

答案 253 :(得分:4)

InternalsVisibleToAttribute指定仅在当前程序集中通常可见的类型对另一个程序集可见。 Article on msdn

答案 254 :(得分:4)

  • 附加到类型以进行制作 可以为空,ex:int?
  • “c:\ dir”而不是 @“C:\ dir”

答案 255 :(得分:4)

我认为很多人都知道C中的指针,但不确定它是否适用于C#。您可以在不安全的上下文中使用C#中的指针:

static void Main()
{
    int i;
    unsafe
    {               
        // pointer pi has the address of variable i
        int* pi = &i; 
        // pointer ppi has the address of variable pi
        int** ppi = &pi;
        // ppi(addess of pi) -> pi(addess of i) -> i(0)
        i = 0;
        // dereference the pi, i.e. *pi is i
        Console.WriteLine("i = {0}", *pi); // output: i = 0
        // since *pi is i, equivalent to i++
        (*pi)++;
        Console.WriteLine("i = {0}", *pi); // output: i = 1
        // since *ppi is pi, one more dereference  *pi is i 
        // equivalent to i += 2
        **ppi += 2;
        Console.WriteLine("i = {0}", *pi);// output: i = 3
    }
    Console.ReadLine();
}

答案 256 :(得分:3)

嗯...... 不要使用它 ,但是很多人不知道C#支持邪恶的goto:)

static void Example()
{
    int i = 0;
top:
    Console.WriteLine(i.ToString());
    if (i == 0)
    {
        i++;
        goto top;
    }
}

答案 257 :(得分:3)

ThreadStaticAttribute是我的最爱。此外,NonSerializableAttribute也很有用。 (你能告诉我使用远程处理做了很多服务器吗?)

答案 258 :(得分:3)

“TODO”属性和任务列表

//TODO: [something] 

将其添加到您的代码中(间距很重要)会在您的任务列表中抛出一个项目,双击该项目会将您跳转到代码中的相应位置。

答案 259 :(得分:3)

我不知道哪些Generic方法可以帮助避免使用Method Overloadding。 下面是重载方法,用于打印int和double数字。

    private static void printNumbers(int [] intNumbers)
    { 
        foreach(int element in intNumbers)
        {
            Console.WriteLine(element);
        }

    }

    private static void printNumbers(double[] doubleNumbers)
    {
        foreach (double element in doubleNumbers)
        {
            Console.WriteLine(element);
        }
    }

有助于为上述两种方法提供一种方法的通用方法

    private static void printNumbers<E>(E [] Numbers)
    {
        foreach (E element in Numbers)
        {
            Console.WriteLine(element);
        }
    }

答案 260 :(得分:3)

起初 - DebuggerTypeProxy

[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable : Hashtable
{
    private const string TestString = 
        "This should not appear in the debug window.";

    internal class HashtableDebugView
    {
        private Hashtable hashtable;
        public const string TestStringProxy = 
            "This should appear in the debug window.";

        // The constructor for the type proxy class must have a 
        // constructor that takes the target type as a parameter.
        public HashtableDebugView(Hashtable hashtable)
        {
            this.hashtable = hashtable;
        }
    }
}

第二名:

ICustomTypeDescriptor

答案 261 :(得分:3)

绝对是Func&lt;&gt;与.NET 3.5中的语句lambdas一起使用时的类型。这些允许自定义功能,并且可以非常有助于提供用户可自定义的对象而无需对其进行子类化或诉诸某些有限的系统,例如跟踪列出用户想要监视的按钮或键的变量。此外,它们可以像常规方法一样调用,并且可以像变量一样分配。我能想到的唯一缺点就是你只限于5个参数!虽然到那时你可能想要考虑一个不同的解决方案...... 编辑:提供一些例子。

...
public Func<InputHelper, float> _horizontalCameraMovement = (InputHelper input) => 
{
    return (input.LeftStickPosition.X * _moveRate) * _zoom;
}
public Func<InputHelper, float> _verticalCameraMovement = (InputHelper input) => 
{
    return (-input.LeftStickPosition.Y * _moveRate) * _zoom;
}
...
public void Update(InputHelper input)
{
    ...
    position += new Vector2(_horizontalCameraMovement(input), _verticalCameraMovement(input));
    ...
}

在此示例中,您可以编写一个执行任意计算的函数,并返回一个浮点数,用于确定相机移动的数量。不是最好的代码,但它得到了重点。

private int foo;
public int FooProperty {
    get
    {
        if (_onFooGotten() == true)
            return _foo;
    }
    set
    {
        if (onFooSet() == true)
            _foo = value;
    }
}
...
public Func<bool> _onFooGotten = () => 
{
    //do whatever...
    return true;
}
public Func<bool> _onFooSet = () =>
{
    //do whatever...
    return true;
}

这不是最好的例子(因为我还没有真正探索过这个用法),但它显示了一个使用lambda函数进行快速事件提升的示例而没有代理的麻烦。 编辑:想到另一个。 Nullables! C#与可选参数最接近的东西。

答案 262 :(得分:3)

参考帖子w / perma链接“Hidden Features of C#?”,还有另一种方法可以实现相同的 - 缩进/换行符。看看这个......

XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.NewLineOnAttributes = true;
xmlWriterSettings.Indent = true;


XmlWriter xml = XmlWriter.Create(@"C:\file.xml", xmlWriterSettings);

// Start writing the data using xml.WriteStartElement(), xml.WriteElementString(...), xml.WriteEndElement() etc

我不确定这是否是一个未知功能!

答案 263 :(得分:3)

double dSqrd = Math.Pow(d,2.0); 

更准确
double dSqrd = d * d; // Here we can lose precision

答案 264 :(得分:3)

下面的内容并未隐藏,但它非常含蓄。我不知道下面的样本是否已经发布在这里,我看不出有什么好处(可能没有),但我会尝试显示一个“怪异”的代码。以下示例通过C#(delegates / anonymous delegates [lambdas])和闭包中的仿函数模拟for语句。其他流语句如ifif/elsewhiledo/whle也会被模拟,但我不确定switch(也许,我是太懒 :))。我稍微压缩了示例源代码以使其更清晰。

private static readonly Action EmptyAction = () => { };
private static readonly Func<bool> EmptyCondition = () => { return true; };

private sealed class BreakStatementException : Exception { }
private sealed class ContinueStatementException : Exception { }
private static void Break() { throw new BreakStatementException(); }
private static void Continue() { throw new ContinueStatementException(); }

private static void For(Action init, Func<bool> condition, Action postBlock, Action statement) {
    init = init ?? EmptyAction;
    condition = condition ?? EmptyCondition;
    postBlock = postBlock ?? EmptyAction;
    statement = statement ?? EmptyAction;
    for ( init(); condition(); postBlock() ) {
        try {
            statement();
        } catch ( BreakStatementException ) {
            break;
        } catch ( ContinueStatementException ) {
            continue;
        }
    }
}

private static void Main() {
    int i = 0; // avoiding error "Use of unassigned local variable 'i'" if not using `for` init block
    For(() => i = 0, () => i < 10, () => i++,
        () => {
            if ( i == 5 )
                Continue();
            Console.WriteLine(i);
        }
    );
}

如果我没错,这种方法与函数式编程实践相关。我是对的吗?

答案 265 :(得分:3)

最近我了解了String.Join方法。在构建像列这样的字符串以供查询选择时,它非常有用。

答案 266 :(得分:3)

使DataGridView不显示该属性:

[System.ComponentModel.Browsable(false)]
public String LastActionID{get; private set;}

允许您为组件设置友好的显示(如DataGrid或DataGridView):

[System.ComponentModel.DisplayName("Last Action")]
public String LastAction{get; private set;}

对于你的支持变量,如果你不想直接访问它们,那就更难了:

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    private DataController p_dataSources;

答案 267 :(得分:3)

ViewState getter可以是单行的。

使用默认值:

public string Caption
{
    get { return (string) (ViewState["Caption"] ?? "Foo"); }
    set { ViewState["Caption"] = value; }
}

public int Index
{
    get { return (int) (ViewState["Index"] ?? 0); }
    set { ViewState["Index"] = value; }
}

使用null作为默认值:

public string Caption
{
    get { return (string) ViewState["Caption"]; }
    set { ViewState["Caption"] = value; }
}

public int? Index
{
    get { return (int?) ViewState["Index"]; }
    set { ViewState["Index"] = value; }
}

这适用于字典支持的任何内容。

答案 268 :(得分:3)

ContextBoundObject

与.NET一样,不是一个C#的东西。这是实现DI的另一种方式,尽管它可能很难。而且你必须从中继承掉它。

http://msdn.microsoft.com/en-us/library/system.contextboundobject.aspx

当我使用自定义日志记录属性修饰类/方法时,我用它来添加日志记录。

答案 269 :(得分:3)

如果您尝试从项目列表中创建逗号分隔的字符串:

string[] itemList = { "Example 1", "Example 2", "Example 3" };
CommaDelimitedStringCollection commaStr = new CommaDelimitedStringCollection();
commaStr.AddRange(itemList);
//outputs Example 1,Example 2,Example 3

再看看here

答案 270 :(得分:3)

不知道这本身是不是秘密,但我喜欢System.Linq中添加的Enumerable(添加到IEnumerable)类。

http://msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx

虽然已列出yield关键字。迭代器块令人惊叹。我使用它们来构建列表,这些列表将进行测试以确定它们是否是共同素数。它基本上允许你通过一个逐个返回值并随时停止的函数。

哦,当你再也无法优化它时,我几乎忘记了世界上最好的课程。 BackgroundWorker !!!!

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

答案 271 :(得分:3)

仅供参考 - 使用扩展方法枚举二进制操作。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace BinaryOpGenericTest
{
    [Flags]
    enum MyFlags
    {
        A = 1,
        B = 2,
        C = 4

    }

    static class EnumExtensions
    {
        private static Dictionary<Type, Delegate> m_operations = new Dictionary<Type, Delegate>();

        public static bool IsFlagSet<T>(this T firstOperand, T secondOperand) 
                                                  where T : struct
        {

            Type enumType = typeof(T);


            if (!enumType.IsEnum)
            {
                throw new InvalidOperationException("Enum type parameter required");
            }


            Delegate funcImplementorBase = null;
            m_operations.TryGetValue(enumType, out funcImplementorBase);

            Func<T, T, bool> funcImplementor = funcImplementorBase as Func<T, T, bool>;

            if (funcImplementor == null)
            {
                funcImplementor = buildFuncImplementor(secondOperand);
            }



            return funcImplementor(firstOperand, secondOperand);
        }


        private static Func<T, T, bool> buildFuncImplementor<T>(T val)
                                                            where T : struct
        {
            var first = Expression.Parameter(val.GetType(), "first");
            var second = Expression.Parameter(val.GetType(), "second");

            Expression convertSecondExpresion = Expression.Convert(second, typeof(int));
            var andOperator = Expression.Lambda<Func<T, T, bool>>(Expression.Equal(
                                                                                                       Expression.And(
                                                                                                            Expression.Convert(first, typeof(int)),
                                                                                                             convertSecondExpresion),
                                                                                                       convertSecondExpresion),
                                                                                             new[] { first, second });
            Func<T, T, bool> andOperatorFunc = andOperator.Compile();
            m_operations[typeof(T)] = andOperatorFunc;
            return andOperatorFunc;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            MyFlags flag = MyFlags.A | MyFlags.B;

            Console.WriteLine(flag.IsFlagSet(MyFlags.A));            
            Console.WriteLine(EnumExtensions.IsFlagSet(flag, MyFlags.C));
            Console.ReadLine();
        }
    }
}

答案 272 :(得分:3)

返回IQueryable投影

protected void LdsPostings_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{   
    var dc = new MyDataContext();
    var query = dc.Posting.AsQueryable();

    if (isCondition1)
    {
        query = query.Where(q => q.PostedBy == Username);
        e.Result = QueryProjection(query);
        return;
    }

    ...

    if (isConditionN)
    {
        query = query.Where(q => q.Status.StatusName == "submitted");
        query = query.Where(q => q.ReviewedBy == Username);
        e.Result = QueryProjection(query);
        return;
    }
}

而不是多次编码投影,创建一个方法:

private IQueryable QueryProjection(IQueryable<Posting> query)
{
    return query.Select(p => new
    {
        p.PostingID,
        p.Category.CategoryName,
        p.Type.TypeName,
        p.Status.StatusName,
        p.Description,
        p.Updated,
        p.PostedBy,
        p.ReviewedBy,
    });
}

答案 273 :(得分:2)

在lambda发挥作用之前,它是匿名代表。这可以用于类似于Ruby的blockgiven的一揽子代码。我还没有测试过lambda是如何工作的,因为到目前为止我想坚持使用.NET 2.0。

例如,当您想要确保记得关闭HTML标记时:

MyHtmlWriter writer=new MyHtmlWriter();
writer.writeTag("html", 
  delegate ()
  { 
    writer.writeTag("head", 
       delegate() 
       { 
           writer.writeTag("title"...);
       }
    )
  })

我确信如果lambda是一个选项,可以产生更清晰的代码:)

答案 274 :(得分:2)

在处理C ++和C#之间的互操作时,很多人都没有意识到C ++ / CLI是一个很好的选择。

假设你有一个C ++ DLL和一个依赖于C ++ DLL的C#DLL。通常,最简单的技术是使用/ clr开关编译C ++ DLL的一些(或所有)模块。让C#调用C ++ DLL就是在C ++ DLL中编写托管C ++包装类。 C ++ / CLI类可以比C#更无缝地调用本机C ++代码,因为C ++编译器将自动为您生成P /调用,具有专门用于互操作的库,以及用于互操作的语言功能,如pin_ptr。它允许托管代码和本机代码在同一个二进制文件中共存。

在C#端,您只需像调用其他任何.NET二进制文件一样调用DLL。

答案 275 :(得分:2)

PreviousPage属性:

“System.Web.UI.Page表示将控件转移到当前页面的页面。”

非常有用。

答案 276 :(得分:2)

小心使用时,重选是如此强大。我在电子邮件模板系统中使用它。模板管理器将被传递一个对象,并且html模板将具有引用的属性,这些字段可以使用反射从传递的对象中检索。工作得非常好。

答案 277 :(得分:2)

我必须承认,我不确定这比普通的ASP.NET转发器onItemDatabound演员代码更好还是更差,但无论如何这里是我的5美分。

MyObject obj = e.Item.DataItem as MyObject;
if(obj != null)
{
  //Do work
}

答案 278 :(得分:2)

@ Robbie Rocketpants

  

“但我的直觉告诉我这个   最多会削减两个类型的角色   操作最多只有一个。“

如果按照示例1中的建议(使用is&amp; as)进行强制转换,则会导致对“is”运算符的2次调用。因为当你执行“c = obj as MyClass”时,首先它在幕后调用“is”,然后如果失败则它只返回null。

如果您按照示例2中的建议进行演员表,

c = (MyClass)obj

然后这实际上再次执行“is”操作,然后如果它检查失败,则抛出异常(InvalidCastException)。

所以,如果你想做一个轻量级的动态演员,最好做你提供的第三个例子:

MyClass c;
if (obj is MyClass)
{
    c = obj as MyClass
}

if (c != null)
{
}

<强> VS

MyClass c = obj as MyClass;

if (c != null)
{
}

你可以看到哪个更快,更简洁,更清晰。

答案 279 :(得分:2)

trick for calling private methods using Delegate.CreateDelegate非常整洁。

var subject = new Subject();
var doSomething = (Func<String, String>)
    Delegate.CreateDelegate(typeof(Func<String, String>), subject, "DoSomething");
Console.WriteLine(doSomething("Hello Freggles"));

Here's a context where it's useful

答案 280 :(得分:2)

  

我想如果你必须使用可空的   类型,最好使用Nullable&lt; .T&gt;   而不是问号   符号。它让人眼前一亮   很明显,魔法正在发生。不   确定为什么有人会想要使用   可空&LT; .bool&GT;虽然。

在VB.NET Web服务中,参数可能无法通过传递(因为合作伙伴请求不一致或不可靠),但必须针对建议的类型传递验证(“if is search request”的布尔值)。将其归结为“管理层的另一项需求”......

...是的,我知道有些人认为这不是做这些事情的正确方法,但 IsSearchRequest As Nullable(Of Boolean)让我在那个晚上失去理智!

答案 281 :(得分:2)

BCL中的一些并发实用程序可能有资格成为隐藏功能。

类似System.Threading.Monitor的东西由lock关键字在内部使用;显然在C#中,lock关键字是可取的,但有时候知道如何在较低级别完成事情是值得的。我不得不锁定C ++ / CLI,因此我通过调用Monitor.Enter()和Monitor.Exit()来封装一段代码。

答案 282 :(得分:2)

通过yield获取IEnumerable而不显式创建IEnumerable对象的另一种方法

public IEnumerable<Request> SomeMethod(IEnumerable<Request> requests)
{
    foreach (Request request in requests)
       yield return DoSomthing(request);
}

答案 283 :(得分:2)

上面提到了List.ForEach; 2.0引入了一系列基于谓词的集合操作 - Find,FindAll,Exists等。再加上匿名委托,您几乎可以实现3.5的lambda表达式的简单性。

答案 284 :(得分:2)

大多数P/Invoke的东西都有点奇怪。

属性示例:

[DllImport ("gdi32.dll")] 
[return : MarshalAs(UnmanagedType.I4)]
[StructLayout(LayoutKind.Sequential)]

答案 285 :(得分:2)

不确定微软是否会喜欢这个问题,特别是有这么多回复。 我相信我曾经听过一位微软负责人说:

  

隐藏的功能是浪费的功能

......或者那种效果。

答案 286 :(得分:2)

在包含escape char的字符串之前使用@。 基本上,当使用物理路径分配字符串变量时,每个人都使用'\',其中转义字符存在于字符串中。

e.g。 string strPath =“D:\ websites \ web1 \ images \”;

但是在字符串值之前使用@可以忽略转义字符。

e.g。 string strPath = @“D:\ websites \ web1 \ images \”;

答案 287 :(得分:1)

如果允许第三方扩展程序,那么C5Microsoft CCR(请参阅this blog post以获得快速介绍)是必须知道的。

C5补充了.Net的一些缺乏集合库(不是Set ???),CCR使并发编程变得更容易(我听说它是​​由于与Parallel Extensions合并而来)。

答案 288 :(得分:1)

没有隐藏,但非常整洁。我发现这是一个简单的if-then-else的简洁替代品,只根据条件分配一个值。

string result = 
              i < 2 ?               //question
              "less than 2" :       //answer
              i < 5 ?               //question
             "less than 5":         //answer   
              i < 10 ?              //question
              "less than 10":       //answer
              "something else";     //default answer 

答案 289 :(得分:1)

Exception Filters。所以“隐藏”你甚至不能使用它们(至少从C#开始)而没有后期编译补丁;)

答案 290 :(得分:1)

如果要阻止垃圾收集器运行对象的终结器,只需使用GC.SuppressFinalize(object);。同样,GC.KeepAlive(object);将阻止垃圾收集器通过引用它来收集该对象。不是很常用,至少在我的经验中,但很高兴知道以防万一。

答案 291 :(得分:1)

有些人?奇怪:)

Delegate target =
  (target0 = target as CallTargetWithContext0) ??
  (target1 = target as CallTargetWithContext1) ??
  (target2 = target as CallTargetWithContext2) ??
  (target3 = target as CallTargetWithContext3) ??
  (target4 = target as CallTargetWithContext4) ??
  (target5 = target as CallTargetWithContext5) ??
  ((Delegate)(targetN = target as CallTargetWithContextN));

有趣的是要注意由于某种原因需要的最后一次演员表。错误或设计?

答案 292 :(得分:1)

根据周围类的泛型类型分隔静态字段。

    public class StaticConstrucEx2Outer<T> {

 // Will hold a different value depending on the specicified generic type
 public T SomeProperty { get; set; }

 static StaticConstrucEx2Outer() {
  Console.WriteLine("StaticConstrucEx2Outer " + typeof(T).Name);
 }

 public class StaticConstrucEx2Inner<U, V> {

  static StaticConstrucEx2Inner() {

   Console.WriteLine("Outer <{0}> : Inner <{1}><{2}>",
    typeof(T).Name,
    typeof(U).Name,
    typeof(V).Name);
  }

  public static void FooBar() {}
 }

 public class SCInner {

  static SCInner() {
   Console.WriteLine("SCInner init <{0}>", typeof(T).Name);
  }

  public static void FooBar() {}
 }
}


StaticConstrucEx2Outer<int>.StaticConstrucEx2Inner<string, DateTime>.FooBar();
StaticConstrucEx2Outer<int>.SCInner.FooBar();

StaticConstrucEx2Outer<string>.StaticConstrucEx2Inner<string, DateTime>.FooBar();
StaticConstrucEx2Outer<string>.SCInner.FooBar();

StaticConstrucEx2Outer<string>.StaticConstrucEx2Inner<string, Int16>.FooBar();
StaticConstrucEx2Outer<string>.SCInner.FooBar();

StaticConstrucEx2Outer<string>.StaticConstrucEx2Inner<string, UInt32>.FooBar();

StaticConstrucEx2Outer<long>.StaticConstrucEx2Inner<string, UInt32>.FooBar();

将产生以下输出

Outer <Int32> : Inner <String><DateTime>
SCInner init <Int32>

Outer <String> : Inner <String><DateTime>
SCInner init <String>

Outer <String> : Inner <String><Int16>

Outer <String> : Inner <String><UInt32>

Outer <Int64> : Inner <String><UInt32>

答案 293 :(得分:1)

当您需要(a)在对象之间同步通信事件的发生时,有一个名为 ISynchronizeInvoke 的特殊用途界面。

引用MSDN文章(link):

  

实现此接口的对象可以接收事件已发生的通知,并且可以响应有关该事件的查询。通过这种方式,客户可以确保在提交后续请求之前处理了一个请求,该请求取决于第一个请求的完成。

这是一个通用的包装器:

protected void OnEvent<T>(EventHandler<T> eventHandler, T args) where T : EventArgs
{
    if (eventHandler == null) return;

    foreach (EventHandler<T> singleEvent in eventHandler.GetInvocationList())
    {
        if (singleEvent.Target != null && singleEvent.Target is ISynchronizeInvoke)
        {
            var target = (ISynchronizeInvoke)singleEvent.Target;

            if (target.InvokeRequired) {
                target.BeginInvoke(singleEvent, new object[] { this, args });
                continue;
            }
        }
        singleEvent(this, args);
    }
}

以下是一个示例用法:

public event EventHandler<ProgressEventArgs> ProgressChanged;

private void OnProgressChanged(int processed, int total)
{
    OnEvent(ProgressChanged, new ProgressEventArgs(processed, total));
}

答案 294 :(得分:1)

Here is a TIP如何使用#Region指令来记录您的代码。

答案 295 :(得分:0)

我不知道这是否是一个隐藏的功能(“”)。任何字符串函数。