1473

从这个问题中了解到以下内容后,我想到了这一点:

where T : struct

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

我们中的一些人甚至掌握了诸如泛型匿名类型lambdasLINQ之类的东西......

但是,即使是 C# 爱好者、爱好者、专家也几乎不知道的 C# 最隐藏的特性或技巧是什么?

以下是迄今为止揭示的功能:


关键词

属性

句法

语言特点

Visual Studio 功能

框架

方法和属性

提示与技巧

其他

4

296 回答 296

751

这本身不是 C#,但我还没有看到任何人真正使用System.IO.Path.Combine()到他们应该使用的程度。其实整个 Path 类真的很有用,只是没人用!

我敢打赌,每个生产应用程序都有以下代码,即使它不应该:

string path = dir + "\\" + fileName;
于 2008-08-13T01:53:50.460 回答
583

lambdas and type inference are underrated. Lambdas can have multiple statements and they double as a compatible delegate object automatically (just make sure the signature match) as in:

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

Note that I don't have a new CancellationEventHandler nor do I have to specify types of sender and e, they're inferable from the event. Which is why this is less cumbersome to writing the whole delegate (blah blah) which also requires you to specify types of parameters.

Lambdas don't need to return anything and type inference is extremely powerful in context like this.

And BTW, you can always return Lambdas that make Lambdas in the functional programming sense. For example, here's a lambda that makes a lambda that handles a Button.Click event:

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

Note the chaining: (dx, dy) => (sender, e) =>

Now that's why I'm happy to have taken the functional programming class :-)

Other than the pointers in C, I think it's the other fundamental thing you should learn :-)

于 2008-08-26T18:34:44.433 回答
527

里克斯特拉尔

可以连环吗??运算符,以便您可以进行一堆空值比较。

string result = value1 ?? value2 ?? value3 ?? String.Empty;
于 2008-08-19T05:43:53.457 回答
453

别名泛型:

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

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

当您在很多地方使用相同的通用大长复杂事物时使用它。

于 2008-09-16T16:53:37.230 回答
437

CLR 通过 C#

在规范化字符串时,强烈建议您使用 ToUpperInvariant 而不是 ToLowerInvariant,因为Microsoft 已经优化了执行大写比较的代码

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

于 2008-08-15T11:06:48.747 回答
407

我最喜欢的技巧是使用空合并运算符和括号为我自动实例化集合。

private IList<Foo> _foo;

public IList<Foo> ListOfFoo 
    { get { return _foo ?? (_foo = new List<Foo>()); } }
于 2008-09-12T13:25:55.610 回答
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 关于此主题的博客文章(以及可能的缺点)。

于 2008-08-12T21:57:39.267 回答
304

其他一切,加上

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();
于 2008-08-12T18:23:40.587 回答
285

我有一段时间不知道“as”关键字。

MyClass myObject = (MyClass) obj;

对比

MyClass myObject = obj as MyClass;

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

于 2008-08-12T16:42:04.113 回答
261

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

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()}
于 2008-08-13T07:39:13.493 回答
254

泛型类型中的“默认”关键字:

T t = default(T);

如果 T 是引用类型,则结果为“null”,如果是 int,则为 0,如果是布尔型,则为 false,等等。

于 2008-08-13T10:20:07.147 回答
225

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

于 2008-08-12T16:59:40.460 回答
220

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

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

如果你有

string s = @"cat
             dog
             fish"

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

cat
             dog
             fish
于 2008-08-13T02:07:26.267 回答
219

我认为 C# (.NET 3.5) 中最被低估和鲜为人知的特性之一是Expression Trees尤其是与泛型和 Lambda 结合使用时。这是 NInject 和 Moq 等较新的库正在使用的 API 创建方法。

例如,假设我想向 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);
    }
}

这是我现在爱上 Lambda 和表达式树的一个重要原因。

于 2008-09-09T21:52:00.237 回答
208

产量”会出现在我的脑海中。[DefaultValue()]等一些属性也是我的最爱。

var ”关键字比较知名,但您也可以在 .NET 2.0 应用程序中使用它(只要您使用 .NET 3.5 编译器并将其设置为输出 2.0 代码)似乎不太为人所知出色地。

编辑:kokos,感谢您指出 ?? 运营商,确实很有用。由于搜索它有点困难(因为 ?? 只是被忽略了),这里是该运算符的 MSDN 文档页面:?? 运算符(C# 参考)

于 2008-08-12T16:34:44.970 回答
197

我倾向于发现大多数 C# 开发人员不知道“可为空”类型。基本上,可以具有空值的原语。

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

将可空的双精度数 num1设置为空,然后将常规双精度数 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。检查链接以获取更多详细信息

于 2008-08-12T17:07:59.350 回答
192

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

__makeref

__reftype

__refvalue

__arglist

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

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

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

最有用的“隐藏”功能是 yield return 关键字。它并不是真正隐藏的,但很多人并不知道它。LINQ 建立在此之上;它允许通过在后台生成状态机来延迟执行查询。Raymond Chen 最近发布了关于内部、坚韧不拔的细节

于 2008-08-12T18:50:29.720 回答
184

纯粹、安全的 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 添加;

于 2008-09-23T20:39:01.003 回答
175

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

var @object = new object();
var @string = "";
var @if = IpsoFacto(); 
于 2008-08-18T01:45:02.193 回答
167

如果您想退出程序而不调用任何 finally 块或终结器,请使用FailFast

Environment.FailFast()
于 2008-10-13T22:25:51.980 回答
153

Returning anonymous types from a method and accessing members without reflection.

// 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;
}
于 2008-08-17T01:01:28.397 回答
146

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

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

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

于 2008-08-12T18:38:16.157 回答
141

混合。基本上,如果你想为几个类添加一个特性,但不能为所有类使用一个基类,让每个类实现一个接口(没有成员)。然后,为接口编写一个扩展方法,即

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

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

于 2008-10-26T19:04:33.183 回答
130

不知道为什么有人会想要使用 Nullable<bool> 。:-)

对,错,文件未找到

于 2008-08-12T18:53:44.333 回答
116

This one is not "hidden" so much as it is misnamed.

A lot of attention is paid to the algorithms "map", "reduce", and "filter". What most people don't realize is that .NET 3.5 added all three of these algorithms, but it gave them very SQL-ish names, based on the fact that they're part of LINQ.

"map" => Select
Transforms data from one form into another

"reduce" => Aggregate
Aggregates values into a single result

"filter" => Where
Filters data based on a criteria

The ability to use LINQ to do inline work on collections that used to take iteration and conditionals can be incredibly valuable. It's worth learning how all the LINQ extension methods can help make your code much more compact and maintainable.

于 2008-08-16T23:55:28.373 回答
115
Environment.NewLine

对于系统独立的换行符。

于 2008-09-01T00:03:41.560 回答
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"
于 2008-08-18T22:29:45.020 回答
104
  1. ?? - 合并运算符
  2. using ( statement / directive ) - 很棒的关键字,不仅可以用于调用 Dispose
  3. 只读- 应该更多地使用
  4. netmodules - 太糟糕了,Visual Studio 不支持
于 2008-08-12T16:35:55.703 回答
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 的内部结构了解得不够多,无法确定,但我的直觉告诉我,这会将最多两种类型转换操作减少到最多一种。无论哪种方式,都不太可能破坏处理银行;就个人而言,我认为后一种形式看起来也更干净。

于 2008-08-12T18:03:12.203 回答
98

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

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

可以浓缩为:

x = (x==1) ? 2 : 3;
于 2008-08-19T15:54:52.677 回答
94

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

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

变成

if( myString.Equals( theirString, StringComparison.OrdinalIgnoreCase ) ){ ... }
于 2009-04-15T00:23:53.073 回答
79

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

string hello = "world";
var o = new { hello };
Console.WriteLine(o.hello);
于 2008-10-17T16:41:51.873 回答
75

老实说,根据定义,专家应该知道这些东西。但要回答您的问题:内置类型表(C# 参考)

数字的编译器标记因以下原因而广为人知:

Decimal = M
Float = F
Double = D

// for example
double d = 30D;

然而,这些更模糊:

Long = L
Unsigned Long = UL
Unsigned Int = U
于 2008-08-12T16:38:50.703 回答
75

I like looking up stuff in a list like:-

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

Rather than:-

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

Doesn't come up that much in practice, but the idea of matching items against the subject of the search can be really quite useful + succinct.

于 2008-08-28T20:59:59.060 回答
73

InternalsVisibleTo属性并不为人所知,但在某些情况下可以派上用场。它基本上允许另一个程序集能够访问定义程序集的“内部”元素。

于 2008-09-05T16:10:21.047 回答
72

下面是 C# 4.0 中字符串类的一个新方法:

String.IsNullOrWhiteSpace(String value)

是时候了。

于 2010-06-22T03:59:04.763 回答
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);

有关更多信息,请参阅“ C# 中的隐式方法组转换”。

于 2008-10-06T15:30:27.870 回答
68
  • System.Transactions 中的TransactionScope 和DependentTransaction是在 .NET 中使用事务处理的轻量级方式 - 它也不仅仅适用于数据库事务
  • String.IsNullOrEmpty 是一个令我惊讶的是很多开发人员都不知道
  • List.ForEach - 使用委托方法遍历您的通用列表

还有更多,但那是我头顶上最明显的三个……

于 2008-08-12T16:45:22.813 回答
68

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

于 2010-06-22T19:22:03.763 回答
66

Dictionary.TryGetValue(K key, out V value)

用作支票和入场券。而不是;

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

你可以这样做;

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

并且值已设置。

于 2008-09-19T20:02:05.340 回答
65

条件字符串。格式:

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

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

例如

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

string pos = 1.ToString(format);     // 001
string neg = (-1).ToString(format);  // -1
string zer = 0.ToString(format);     // (0)
于 2009-08-05T05:57:55.170 回答
64

事件实际上是引擎盖下的委托,任何委托对象都可以附加多个函数,并分别使用 += 和 -= 运算符与其分离。

事件也可以通过添加/删除来控制,类似于 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;
于 2008-08-18T07:33:17.560 回答
61

不要忘记goto

于 2008-09-18T02:33:51.023 回答
56

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


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

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

于 2008-10-18T11:54:28.583 回答
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;
}
于 2008-09-15T14:58:26.657 回答
55

其他未充分使用的运算符是checkedand unchecked

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
于 2008-12-10T13:11:49.433 回答
55

使用“投掷”;而不是“扔前;” 保留堆栈跟踪

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

于 2009-06-16T17:14:06.730 回答
48

我遇到的一些隐藏功能:

  • stackalloc这使您可以在堆栈上分配数组
  • 没有显式参数列表的匿名方法,可以隐式转换为任何具有非 out/ref 参数的委托类型(对于事件非常方便,如前面的评论中所述)
  • 很多人不知道真正的事件是什么(添加/删除一对方法,例如属性的 get/set);C# 中的类字段事件确实声明了一个变量一个事件
  • ==and!=运算符可以重载以返回除 之外的类型bool。奇怪但真实。
  • C# 3 中的查询表达式翻译在某些方面确实“简单”——这意味着您可以让它做一些非常奇怪的事情
  • 可空类型具有特殊的装箱行为:空值被装箱到空引用,并且您也可以从空拆箱到可空类型。
于 2008-09-26T15:28:11.950 回答
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 键并选择矩形,无需取消注释行。

看一下这个。

于 2009-11-09T06:58:35.877 回答
46

@大卫在达科他州:

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

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

new String('-',22);
于 2008-09-05T13:54:30.030 回答
46

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

于 2008-09-12T18:24:24.410 回答
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(){}
于 2008-09-09T14:04:46.413 回答
45

params 关键字,即

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

叫像

DoSomething(“The”, “cat”, “sat”, “on”, “the” ,”mat”);
于 2008-10-03T05:34:22.927 回答
44

Foreach 使用鸭子打字

转述,或无耻地从Krzysztof Cwalinas 的博客中窃取。比什么都有趣的琐事。

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

  • 您的对象提供了 一个公共方法GetEnumerator
    • 不带参数
    • 返回一个有两个成员的类型
      1. 返回布尔值的无参数方法 MoveNext
      2. 带有返回 Object的 getter的属性 Current

例如,

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!");
}
于 2008-09-04T21:06:29.627 回答
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

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

例如:

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抛出 a 并且您无法深入到有问题的代码行。相反,您必须检查TypeInitializationException'sInnerException成员,这是具体原因。

于 2008-09-19T07:48:12.320 回答
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; }
}
于 2008-08-28T21:46:35.407 回答
39

C# + CLR:

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

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

  3. ThreadStatic变量:这几年只有一种情况我发现 ThreadStatic 变量绝对是天赐之物,不可或缺。例如,当您想为整个调用链做某事时,它们非常有用。

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

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

  6. 我使用的一个方便的特性是DataRow[columnName].ToString()总是返回非空值。如果数据库中的值为 NULL,则会得到空字符串。

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


#if DEBUG  
    if (Debugger.IsAttached)  
        Debugger.Break();  
#endif
  1. 您可以给复杂难看的泛型类型加上别名,这样您就不必一次又一次地复制粘贴它们。您也可以在一处更改该类型。例如,

    using ComplicatedDictionary = Dictionary<int, Dictionary<string, object>>;
    ComplicatedDictionary myDictionary = new ComplicatedDictionary();
于 2009-11-10T11:28:19.000 回答
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);

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

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

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);
于 2008-12-24T18:10:36.670 回答
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)) {
    ...
}

这当然只是一个例子——这些方法可能需要更多的工作......

于 2009-01-02T16:26:32.977 回答
36

能够让枚举类型具有除 int 以外的值(默认值)

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

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

MyEnum e = (MyEnum)123;
于 2008-08-14T22:31:26.180 回答
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 调用时间的问题。这种相对于开发分析(例如在 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 派生类中,您必须重写Invoke:

[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派生。我希望这对某人有帮助。

于 2010-06-29T05:18:36.120 回答
36

I just found out about this one today -- and I've been working with C# for 5 years!

It's the namespace alias qualifier:

extern alias YourAliasHere;

You can use it to load multiple versions of the same type. This can be useful in maintenance or upgrade scenarios where you have an updated version of your type that won't work in some old code, but you need to upgrade it to the new version. Slap on a namespace alias qualifier, and the compiler will let you have both types in your code.

于 2008-09-05T16:53:07.433 回答
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"; 
} 

对于有眼光的程序员。

于 2010-03-22T20:05:06.127 回答
34

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

        int? x = null;
        int y;
        if (x.HasValue)
            y = x.Value;
于 2008-08-18T23:47:06.157 回答
33

我最喜欢的是

global::

使用我们的一些 3rd 方代码提供程序来逃避命名空间地狱的关键字......

例子:

global::System.Collections.Generic.List<global::System.String> myList =
    new global::System.Collections.Generic.List<global::System.String>();
于 2008-08-15T11:34:02.497 回答
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))
{    }

这与我的不同。

于 2009-09-12T19:47:40.967 回答
31

I've read through all seven pages, and I'm missing these:

String.Join

I've seen a lot of for-loops to convert a list of items to a string with separators. It's always a pain to make sure you doin't start with a separator and don't end with a separator. A built-in method makes this easier:

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

TODO in comment

Not really a C# feature, more of a Visual Studio feature. When you start your comment with TODO, it's added to your Visual Studio Task List (View -> Task List. Comments)

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

Extension methods meets Generics

You can combine extension methods with Generics, when you think of the tip earlier in this topic, you can add extensions to specific interfaces

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

Enumerable.Range

Just want a list of integers?

Enumerable.Range(0, 15)

I'll try to think of some more...

于 2009-07-11T19:01:09.543 回答
31

类型定义

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

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

并将其声明为

ListOfDictionary list = new ListOfDictionary();
于 2010-06-13T05:14:40.770 回答
31

宽度string.Format()

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

生产

替代文字

来自 Prabir 的博客 | 隐藏的 C# 功能

于 2010-05-27T03:10:14.313 回答
30

我喜欢关键字continue

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

例如:

foreach(object o in ACollection)
{
  if(NotInterested)
     continue;
}
于 2008-09-08T12:49:17.587 回答
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)) {
    ... 
}
于 2008-09-01T05:03:20.607 回答
28

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

  1. 片段(尤其是属性,它在 Visual Studio 2008 中做得更好)
  2. 过时的属性
于 2008-08-12T16:37:19.037 回答
28

@lomaxx 前几天我还了解到(与我学习您的提示的时间相同)是,您现在可以在同一属性上拥有不同的访问级别:

public string Name { get; private set;}

这样,只有类本身可以设置 Name 属性。

public MyClass(string name) { Name = name; }
于 2008-08-19T04:41:58.247 回答
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;
于 2009-09-09T11:31:54.323 回答
27

轻松确定声明变量的类型(来自我的回答):

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

及其名称(借自“获取变量名”):

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'

于 2009-11-24T13:15:08.260 回答
27

一行中的按需字段初始化:

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

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

于 2008-11-18T16:16:26.043 回答
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);
 }
于 2008-08-17T21:13:24.393 回答
27

完全访问调用堆栈:

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

所以,如果你要使用第一个 - 你知道你在哪个函数中。如果你正在创建一个辅助跟踪函数 - 在最后一个之前取一个 - 你会知道你的调用者。

于 2008-10-10T16:22:40.903 回答
26

它实际上不是 C# 的隐藏功能,但我最近发现了WeakReference 类并被它所震撼(尽管这可能是因为它帮助我找到了解决我的特定问题的方法......)

于 2008-08-18T14:43:56.020 回答
26

Environment.UserInteractive属性。

对于 Windows 进程或在没有用户界面的情况下运行的 IIS 等服务,UserInteractive 属性报告为 false。如果此属性为 false,则不要显示模式对话框或消息框,因为没有供用户交互的图形用户界面。

于 2008-10-08T07:45:04.330 回答
26

AppDomain.UnhandledException Event is also candidate for being hidden.

This event provides notification of uncaught exceptions. It allows the application to log information about the exception before the system default handler reports the exception to the user and terminates the application. If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery. Caution is advised, because program data can become corrupted when exceptions are not handled.

We can see, even on this site, a lot of people are wondering why their application is not starting, why it crashed, etc. The AppDomain.UnhandledException event can be very useful for such cases as it provides the possibility at least to log the reason of application failure.

于 2010-06-30T04:20:12.973 回答
26

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

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

于 2009-08-07T06:44:19.817 回答
25

C# ?? 空合并运算符 -

没有真正隐藏,但很少使用。可能是因为很多开发人员在看到条件时会跑得很远?运营商,所以当他们看到这个时,他们会运行两个。用过的:

string mystring = foo ?? "foo was null"

而不是

string mystring;
if (foo==null)
    mystring = "foo was null";
else
    mystring = foo;
于 2008-08-26T12:54:41.083 回答
25

#if DEBUG预处理器指令。它对测试和调试很有用(尽管我通常更喜欢走单元测试路线)。

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

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

于 2008-08-26T22:19:01.507 回答
25

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

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());
于 2010-01-25T13:55:03.170 回答
24

真假运算符真的很奇怪。

更全面的例子可以在这里找到。

编辑:有相关的 SO 问题C# 中的 false 运算符有什么用?

于 2008-08-28T12:55:57.850 回答
24

Partial Methods

Charlie Calvert explains partial methods on his blog

Scott Cate has a nice partial method demo here

  1. Points of extensibility in Code Generated class (LINQ to SQL, EF)
  2. Does not get compiled into the dll if it is not implemented (check it out with .NET Reflector)
于 2008-08-19T15:23:12.040 回答
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));
}}
于 2008-09-05T07:49:27.087 回答
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 章:接口,关于泛型和接口约束的部分。

另请参阅对另一个问题的回答。

于 2009-11-30T15:37:31.573 回答
22

几乎所有很酷的都被提到了。不确定这个是否众所周知

C# 属性/字段构造函数初始化:

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

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

我注意到一些有趣的事情——你可以在属性列表的末尾有一个逗号,而不是语法错误。所以这也是有效的:

var foo = new Rectangle() 
{ 
    Fill = new SolidColorBrush(c), 
    Width = 20, 
    Height = 20,
};
于 2008-08-18T23:08:35.830 回答
21

基于这个帖子的标题应该是“尽管认为你已经知道一切,但直到最近你才知道的关于 C#的事情”,我个人的特点是异步委托。

直到我阅读了 Jeff Richter 的 C#/CLR 书(优秀的书,每个使用 .NET 的人都应该阅读它),我不知道您可以使用/调用任何委托。我倾向于做很多调用(我想这很像代表在内部做的事情),但是添加标准化的连接/集合模式有时可能真的很有用。BeginInvokeEndInvokeThreadPool.QueueUserWorkItemBeginInvoke

于 2008-08-13T08:29:09.287 回答
21

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

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可以放置在扩展方法上的方法,并将导致编译器内联方法定义(这将使这种方法几乎是标准的,并且是最快的)。

编辑:根据评论删除了扩展方法中的临时变量

于 2010-06-22T16:12:29.493 回答
21

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

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

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

于 2008-11-18T20:51:07.910 回答
20

What about IObservable?

Pretty much everybody knows IEnumerable but their mathematical dual seems to be unknown IObservable. Maybe because its new in .NET 4.

What it does is instead of pulling the information (like an enumerable) it pushes information to the subscriber(s) of the observerable.

Together with the Rx extensions it will change how we deal with events. Just to illustrate how powerful it is check a very short example here.

于 2010-04-21T15:41:05.063 回答
20

我参加这个聚会迟到了,所以我的第一个选择已经做出了。但我还没有看到有人提到这个宝石:

.NET Framework 的并行扩展

它有诸如用 Parallel.For 替换或用 Parallel.ForEach 替换 foreach 之类的东西


Parallel Sample :
在您看来,一秒钟可以创建多少个 CLR 对象? 在此处输入图像描述
见下例:

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);
       }
   }
}
于 2008-08-27T21:05:41.940 回答
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;
}

这更加简洁,而且您不会陷入将委托放在包含事件的类或 EventArgs 派生类的 .cs 文件中的两难境地。

于 2009-09-23T09:00:29.407 回答
20

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

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

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

于 2008-12-05T11:10:09.463 回答
20

属性目标

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

[assembly: ComVisible(false)]

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

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

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

于 2009-06-02T07:20:56.077 回答
20
string.Empty

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

它隐藏得很好,直到有人告诉你它在那里。

于 2010-06-30T09:24:46.087 回答
20

好的,这似乎很明显,但我想提一下Object.Equals方法(静态方法,带有两个参数)。

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

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

当你可以写:

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

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

于 2010-05-25T14:09:06.777 回答
19

C# 3.0 的 LINQ 查询理解是完全成熟的单子理解 就像Haskell 一样(实际上它们是由 Haskell 的一位设计师设计的)。它们适用于任何遵循“LINQ 模式”的泛型类型,并允许您以纯单子函数样式编写,这意味着您的所有变量都是不可变的(就好像您使用的唯一变量是IDisposables 和IEnumerables 在使用foreach语句)。这有助于保持变量声明靠近它们的使用位置,并确保所有副作用都被显式声明(如果有的话)。

 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 */      
    });

 }
于 2009-01-01T16:10:01.197 回答
19

Not really hidden, but useful. When you've got an enum with flags, you can use shift-left to make things clearer. e.g.

[Flags]
public enum ErrorTypes {
    None              = 0,
    MissingPassword   = 1 << 0,
    MissingUsername   = 1 << 1,
    PasswordIncorrect = 1 << 2 
}
于 2010-06-22T12:55:40.147 回答
19

我看到很多人复制Nullable<T>.GetValueOrDefault(T).

于 2008-08-20T15:00:30.173 回答
18

我最喜欢的属性:InternalsVisibleTo

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

将其粘贴在您的 AssemblyInfo.cs 或等效文件中,您的测试程序集就可以完全访问所有需要测试的内部内容。

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

如您所见,测试程序集必须具有强名称才能获得被测程序集的信任。

在 .Net Framework 2.0+、Compact Framework 2.0+ 和 XNA Framework 1.0+ 中可用。

于 2009-04-17T07:09:13.487 回答
17

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

string sql = @"SELECT firstname, lastname, email
               FROM users
               WHERE username = @username AND password = @password";
于 2008-08-28T16:17:15.883 回答
17

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

于 2008-09-01T13:21:10.630 回答
17

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

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

Console.Write(test2); //compile error

test2只存在于括号内。

于 2009-09-16T19:38:58.367 回答
17

需要返回一个空的 IEnumerable?

public IEnumerable<T> GetEnumerator(){
  yield break;
}
于 2009-11-12T19:43:24.913 回答
16

您可以在 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!";
    }
}
于 2008-11-19T16:28:25.427 回答
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'

更多详细信息,请参阅如何在 C# 中找出变量或参数名称?

于 2008-12-16T06:07:30.570 回答
16

您可以将颜色存储在 Enum 中。

public enum MyEnumColors : uint
{
    Normal          = 0xFF9F9F9F,
    Active          = 0xFF8EA98A,
    Error           = 0xFFFF0000
}
于 2010-02-14T18:52:49.937 回答
15

枚举上的FlagsAttribute怎么样?它允许您执行按位运算……我花了很长时间才知道如何在 .NET 中很好地执行按位运算。

于 2008-08-22T03:55:51.533 回答
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);
}

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

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

我真的只是说泛型在坏人手中可能是一个非常强大的野兽。

于 2008-08-12T17:29:29.307 回答
15

使用带有 FlagAttribute 和 enum 的“~”运算符
有时我们会使用带有 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.
 }
于 2010-03-16T15:37:04.987 回答
15

固定语句

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

固定语句设置一个指向托管变量的指针,并在语句执行期间“固定”该变量。

堆栈分配

stackalloc 在栈上分配一块内存。

于 2010-06-30T18:09:05.607 回答
15

您可以使用更少的输入来添加和删除委托。

常用方式:

handler += new EventHandler(func);

少打字方式:

handler += func;
于 2009-06-26T16:13:06.793 回答
15

也有用,但不常用:受约束的执行区域

来自 BCL 团队博客的引述:

存在约束执行区 (CER) 以帮助开发人员编写代码以保持一致性。CLR 不保证开发人员的代码是正确的,但 CLR 确实将所有运行时引起的故障点(即异步异常)提升到代码运行之前或完成之后。结合对开发人员可以在 CER 中添加的内容的限制,这些都是对您的代码是否会执行做出强有力保证的有用方法。CER 是热切准备的,这意味着当我们看到一个时,我们将热切地 JIT 在其静态可发现调用图中找到的任何代码。如果 CLR 的主机关心堆栈溢出,我们也会探测一些堆栈空间(尽管可能没有足够的堆栈空间用于任何任意方法*)。

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

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

于 2010-06-29T06:12:32.977 回答
14

条件属性

允许您告诉编译器在某些条件下(#define)省略对标有属性的方法的调用。

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

于 2008-08-29T21:28:19.343 回答
14

当一个类实现INotifyPropertyChanged并且您想通知绑定系统(WPF、Silverlight 等)一个对象(ViewModel)的多个绑定属性已更改时,您可以使用nullString.Empty引发 PropertyChanged-Event 。

这在 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);
        }
    }
}
于 2010-04-22T07:40:51.540 回答
14

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

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

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

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

于 2008-09-29T16:34:13.247 回答
14

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

    [OperationContract, ServiceKnownType(typeof(Prism)), ServiceKnownType(typeof(Cuboid))]
    Shape GetShape();
于 2010-07-03T17:31:40.200 回答
14

标记我的末端区域...

#region stuff1
 #region stuff1a
 //...
 #endregion stuff1a
#endregion stuff1
于 2008-10-03T05:57:04.743 回答
14

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

@ 特殊字符可用于区分它们:

[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 {}
于 2009-09-12T19:26:18.997 回答
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] );             
}
于 2008-08-13T18:47:41.473 回答
13

如何使用这个:

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

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

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

于 2008-11-19T16:58:38.097 回答
13

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

于 2008-08-15T14:51:42.590 回答
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");
}
于 2009-07-30T04:23:58.397 回答
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();

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

于 2010-01-08T10:03:33.877 回答
13

FlagsAttribute,使用枚举制作位掩码时的一个小但不错的功能:

[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
于 2009-06-05T18:43:55.447 回答
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");

这为您提供了无处不在的完全类型推断的工厂方法!

于 2009-11-20T14:57:05.713 回答
12

可以通过在 a (see ) 中没有代码或switch使用特殊的(see ) 或(see ) 形式来实现通过 -s:casecasecase 0goto casecase 1goto defaultcase 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;
}
于 2008-09-18T06:08:15.720 回答
12

我错过了很长时间的东西:您可以将字符串与

"string".equals("String", StringComparison.InvariantCultureIgnoreCase)

而不是这样做:

"string".ToLower() == "String".ToLower();
于 2008-11-04T23:30:41.453 回答
12

我能想到的一对:

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

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

另一个鲜为人知的特性是覆盖添加/删除事件处理程序:

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

    remove
    {
        // ...
    }
}
于 2009-11-30T17:41:12.223 回答
11

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

例如:

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

这些功能是在 .NET 框架 3.5 版中引入的。

于 2008-12-03T04:45:34.577 回答
11
  1. 我还不能发表评论,但请注意,默认情况下 Visual Studio 2008 会自动跳过属性,因此在这种情况下不再需要 DebuggerStepThrough 属性。

  2. 另外,我没有注意到有人展示了如何声明一个无参数的 lambda(对于实现 Action<> 很有用)

    () => DoSomething(x);

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

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

    (e, _) => DoSomething(e)

它并没有真正忽略它,只是 _ 是一个有效的标识符。所以你不能忽略这样的两个参数,但我认为这是一种巧妙的方式来表明我们不关心那个参数(通常是 EventArgs .Empty)。

于 2008-09-16T13:56:08.140 回答
11

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

它似乎不是一个经常遇到的功能,但实际上它在LINQ to XML ( System.Xml.Linq) 库中使用,您可以在其中将字符串隐式转换为XName对象。例子:

XName tagName = "x:Name";

我在这篇关于如何在 C# 中模拟多重继承的文章中发现了这个特性。

于 2008-09-23T14:44:29.203 回答
11

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

于 2008-08-14T10:59:21.430 回答
11

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

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

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

于 2009-03-06T11:49:20.110 回答
11

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

示例应用程序:您可以为被调用定义一个替代方法,它在ToString()调用ToStringOrEmpty()时将返回空字符串null

于 2009-07-02T00:34:17.423 回答
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);
    }
}

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

于 2009-09-09T11:14:47.410 回答
10

You can change rounding scheme using:

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
于 2010-03-27T23:38:47.077 回答
10

Or赋值运算符非常好。你可以这样写:

x |= y

而不是这个:

x = x | y

如果您必须有一个变量或属性(示例x中)false以.true

于 2009-06-30T08:55:57.547 回答
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()

于 2008-12-13T21:53:01.053 回答
10

TrueForAll 方法List<T>

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

bool a = s.TrueForAll(p => p > 0);
于 2008-12-23T12:27:07.580 回答
10

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

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

于 2009-05-08T15:35:04.417 回答
10

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

[ThreadStatic]
private static int _ThreadStaticInteger;

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

ASP.NET 应用程序线程的另一件事是重用,因此如果您修改该值,它最终可能会被用于另一个页面请求。

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

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

DbTransaction 构造函数将 ThreadStatic 字段设置为其自身,并在 dispose 方法中将其重置为 null。DoQuery 检查静态字段,如果 != null 使用当前事务,如果不是,则默认为其他内容。我们避免了将事务传递给每个方法,而且它可以轻松地将原本不打算与事务一起使用的其他方法包装在事务中......

只有一种用途:)

于 2009-06-19T13:08:28.730 回答
9

如果您希望在 Debug 和 Release 模式之间有不同的行为,预处理器指令可能会很漂亮。

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

于 2008-08-19T16:07:50.390 回答
9
System.Diagnostics.Debug.Assert (false);

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

于 2008-09-23T14:36:02.750 回答
9

Working with enums.

Convert a string to an Enum:

enum MyEnum
{
    FirstValue,
    SecondValue,
    ThirdValue
}

string enumValueString = "FirstValue";
MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), enumValueString, true)
  • I use this to load the value of CacheItemPriority in my ASP.NET applications from a settings table in a database so that I can control caching (along with other settings) dynamically without taking the application down.

When comparing variables of type enum, you don't have to cast to int:

MyEnum val = MyEnum.SecondValue;
if (val < MyEnum.ThirdValue)
{
    // Do something
}
于 2009-04-02T10:35:23.747 回答
9

字符串实习。这是我在这个讨论中还没有看到的一个。它有点晦涩,但在某些情况下它可能很有用。

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

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

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

于 2008-10-01T11:51:29.697 回答
9

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

public void DoStuff<T>(T value);

而不是这样称呼它:

DoStuff<int>(5);

你可以:

DoStuff(5);

它会根据参数的类型计算出泛型类型。

  • 如果您通过反射调用该方法,这将不起作用。
  • 我记得在 Mono 上遇到了一些奇怪的问题。
于 2009-04-02T16:30:33.247 回答
9

IEnumerable's SelectMany,它将列表列表扁平化为单个列表。假设我有一个 列表Orders,并且每个Order列表都有一个LineItems按该顺序排列的列表。

我想知道总LineItems销量...

int totalItems = Orders.Select(o => o.LineItems).SelectMany(i => i).Sum();
于 2008-11-24T12:51:58.030 回答
9

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

IEnumerable <T>.Any();

  • 起初,我使用的是 (IEnumerable <T>.Count() != 0)...
    • 这不必要地导致<T>枚举 IEnumerable 中的所有项目。
  • 作为对此的改进,我继续使用 (IEnumerable <T>.FirstOrDefault() == null)...
    • 哪个更好...
  • 但是 IEnumerable <T>.Any() 是最简洁且性能最好的。
于 2010-03-01T22:37:19.970 回答
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;
    }
}

我认为能够使用 << 和 >> 左右移动字符串或使用 -= 删除遵循正则表达式模式的一组字符串非常酷

myClass tmpClass = new myClass("  HelloWorld123");
tmpClass -= @"World";
tmpClass <<= 2;
Console.WriteLine(tmpClass);
于 2008-08-24T07:52:19.547 回答
8

C# allows you to add property setter methods to concrete types that implement readonly interface properties even though the interface declaration itself has no property setter. For example:

public interface IReadOnlyFoo
{
   object SomeReadOnlyProperty { get; }
}

The concrete class looks like this:

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

What's interesting about this is that the Foo class is immutable if you cast it to the IReadOnlyFoo interface:

// 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;
于 2009-11-05T00:10:43.080 回答
8

你可以打开字符串!

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

非常便利!并且比一堆 if-else 语句更干净

于 2008-10-13T22:32:10.360 回答
8

不是 C# 特定的东西,但我是一个三元操作迷。

代替

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

你可以用简洁的

booleanCondtion ? true operation : false operation;

例如

代替

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

你可以输入

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

它确实有助于编写简洁的代码,但是嵌套这些该死的东西可能很讨厌,而且它们可以用来作恶,但我仍然喜欢这些小傻瓜

于 2008-09-08T22:49:47.673 回答
8

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

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

于 2009-08-07T00:13:41.060 回答
8

而不是像这样做一些俗气的事情:

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

我使用以下内联技巧:

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

当有一个项目时,这将显示“项目”,或者当多于(或少于)1 个时显示“项目”。对于一点专业性来说,没有太多的努力。

于 2009-05-04T19:57:08.820 回答
8

字典初始化器对于需要硬编码某些数据的快速破解和单元测试总是有用的。

var dict = new Dictionary<int, string> { { 10, "Hello" }, { 20, "World" } };
于 2009-12-07T08:26:16.287 回答
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();
    }
于 2010-03-20T18:00:45.117 回答
7

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

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

于 2008-08-20T19:17:16.330 回答
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
        }
    }
于 2008-12-15T15:03:09.210 回答
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,这太糟糕了。

仍然 - 非常隐蔽。:)

于 2008-11-25T22:53:40.513 回答
7

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

private double _Zoom = 1;

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

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

于 2009-06-03T15:03:23.143 回答
7

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

namespace System.Runtime.CompilerServices
{
    public class ExtensionAttribute : Attribute
    { 
    }
}
于 2008-08-14T11:07:01.447 回答
7

高级调试

展示

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

如果您想要更复杂的输出,您可以使用/创建Debugger Visualizer ,此处提供了几个示例。

罢工之子

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

用于框架源的符号服务器

遵循这些说明将允许您逐步了解框架某些部分的源代码。

2010年的变化

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

  • 调试并行任务
  • 并行堆栈允许同时查看多个线程调用堆栈。
  • 历史调试可让您及时查看事件和非局部变量(只要您提前启用收集)。调试方式可能会发生重大变化。
于 2009-06-14T17:31:46.930 回答
7
HttpContext.Current.Server.Execute 

is great for rendering HTML to strings for AJAX callbacks. You can use this with a component instead of piecing together HTML string snippets. I was able to cut page bloat down a couple of hundred KB with virtually no mess. I used it like this:

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();
于 2009-06-22T05:42:31.580 回答
7

Object.ReferenceEquals 方法

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

参数:

  • objA: System.Object - 要比较的第一个对象。
  • objB:System.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 都已被覆盖以比较字符串的内容。

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

于 2008-10-25T09:53:31.090 回答
7

显式接口成员实现,其中实现了接口成员,但隐藏,除非实例被强制转换为接口类型。

于 2008-11-18T15:56:03.277 回答
7

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

于 2009-01-24T05:22:17.283 回答
7

我正在阅读“Pro ASP.NET MVC Framework”(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

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

于 2010-05-14T18:46:21.680 回答
7

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

var pets = new[] { "Cat", "Dog", "Bird" };
于 2009-05-19T15:52:52.263 回答
7

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

Microsoft.VisualBasic.Logging.FileLogTraceListener

MSDN 链接

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

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

于 2009-04-01T21:50:41.820 回答
7

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

于 2009-08-21T11:30:38.153 回答
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"

请注意,这不适用于扩展值类型的扩展方法;看到这个问题

于 2009-06-19T01:59:31.780 回答
7

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

(_, b, __) => b.DoStuff();  // only interested in b here
于 2009-01-31T04:50:20.090 回答
7
[field: NonSerialized]
public event EventHandler Event;

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

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

于 2009-07-22T01:42:45.620 回答
7

我喜欢

#if DEBUG
           //Code run in debugging mode

#else
           //Code run in release mode

#endif
于 2010-04-05T12:25:40.910 回答
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;
    }
}

这里的另一个例子

于 2009-04-26T16:11:10.087 回答
7

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

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

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

于 2010-07-06T19:46:43.967 回答
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',因为它不是委托类型”。

于 2009-05-14T09:05:37.560 回答
7

Eric Lippert 的四个开关怪事

于 2009-08-14T12:13:18.657 回答
7

我认为没有人提到过该附加?在值类型名称之后将使其可为空。

你可以做:

DateTime? date = null;

DateTime 是一个结构。

于 2009-08-07T06:37:19.330 回答
6

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

http://www.codeplex.com/ResourceRefactoring

于 2008-12-16T22:16:59.270 回答
6

Instead of using int.TryParse() or Convert.ToInt32(), I like having a static integer parsing function that returns null when it can't parse. Then I can use ?? and the ternary operator together to more clearly ensure my declaration and initialization are all done on one line in a easy-to-understand way.

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

This is also good to avoid duplicating the left side of an assignment, but even better to avoid duplicating long calls on the right side of an assignment, such as a database calls in the following example. Instead of ugly if-then trees (which I run into often):

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

You can do:

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

Much cleaner and easier to understand

于 2008-10-06T21:16:08.717 回答
6

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

于 2008-11-17T09:28:42.047 回答
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();
}
于 2008-09-19T15:59:09.043 回答
6

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

enum EnumName : [byte, char, int16, int32, int64, uint16, uint32, uint64]
{
    A = 1,
    B = 2
}
于 2009-06-07T07:26:09.073 回答
6

Thought about @dp AnonCast and decided to try it out a bit. Here's what I come up with that might be useful to some:

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

And here's how it might be used:

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)
    };
}
于 2008-08-28T20:07:41.743 回答
6

@布拉德·巴克

我认为如果您必须使用可为空的类型,最好使用 Nullable<.T> 而不是问号表示法。这使得魔法正在发生的事情变得非常明显。不知道为什么有人会想使用 Nullable<.bool> 。:-)

Krzysztof Cwalina(框架设计指南的作者之一)在这里有一篇很好的帖子:http: //blogs.msdn.com/kcwalina/archive/2008/07/16/Nullable.aspx

Mike Hadlow 在Nullability Voodoo上有一篇不错的帖子

于 2008-08-12T18:40:45.340 回答
6

没有特别的顺序:

Lists<>
Mutex

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

于 2008-08-12T19:40:28.030 回答
6

新修饰符

C# 中“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"
    }
}

[Ed:我会因为双关语而获得加分吗?对不起,帮不上忙。]

于 2008-09-17T20:28:37.203 回答
6

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

container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>));
于 2009-09-27T19:04:44.140 回答
6

(我只用过这个)设置一个字段 null 并在没有中间变量的情况下返回它:

try
{
    return _field;
}
finally
{
    _field = null;
}
于 2008-11-18T15:52:15.843 回答
6

Yield 关键字功能强大时经常被忽视。不久前我在博客上讨论过它的好处(不同的处理),并在产量的背后发生,以帮助加深理解。

在 C# 中使用产量

于 2009-06-18T03:44:34.440 回答
6

在阅读有关 .NET 框架开发的书时。一个好的建议是不要使用 bool 来打开或关闭东西,而是使用 ENums。

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

于 2008-08-25T15:09:18.617 回答
6

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

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

我发现这个更小、更干净、更易读:

x = Math.Max(x, lowerBoundary);

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

x = ( x < lowerBoundary) ? lowerBoundary : x;
于 2008-11-04T23:24:03.120 回答
6

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

DateTime? myDate = null;

if (myDate.HasValue)
{
    //doSomething
}
else
{
    //soSomethingElse
}
于 2009-07-22T08:39:34.373 回答
6

刚刚了解了不变性、协变和逆变的含义,我发现了将包含在 .NET 4.0 中的inout泛型修饰符。它们看起来很模糊,以至于大多数程序员都不知道它们。

Visual Studio Magazine 上有一篇文章讨论了这些关键字以及如何使用它们。

于 2009-05-26T21:23:24.767 回答
6

在将它们与以下内容结合之前,我无法弄清楚Convert该类中的某些函数有什么用途(例如 Convert.ToDouble(int)、Convert.ToInt(double))Array.ConvertAll

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

这避免了由定义内联委托/闭包引起的资源分配问题(并且更具可读性):

int[] someArrayYouHaveAsInt;
double[] copyOfArrayAsDouble = Array.ConvertAll<int, double>(
                                someArrayYouHaveAsInt,
                                new Converter<int,double>(
                                  delegate(int i) { return (double)i; }
                                ));
于 2009-05-19T11:00:33.940 回答
6

Mixins 是一个不错的功能。基本上,mixin 让你拥有接口而不是类的具体代码。然后,只需在一堆类中实现接口,您就会自动获得 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。

于 2008-11-06T21:47:46.743 回答
6

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

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

 }
于 2010-05-02T13:17:49.230 回答
6

我将此称为 AutoDebug,因为您可以根据布尔值在需要的时间和地点直接进行调试,该布尔值也可以存储为项目用户设置。

例子:

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

于 2008-12-30T01:40:37.583 回答
6

我发现编译器在使用外部变量进行糖化代码时遇到了什么样的麻烦,这令人难以置信:

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

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

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();

我觉得很酷。

于 2009-05-17T08:41:55.380 回答
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);
于 2009-02-27T00:45:20.403 回答
6

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

环境值属性

这类似于DefaultValueAttribute,但不是提供属性默认的值,而是提供属性用来决定是否从其他地方请求其值的值。例如,对于 WinForms 中的许多控件,它们的ForeColorBackColor属性都有一个AmbientValueofColor.Empty以便它们知道从其父控件中获取它们的颜色。

隔离存储设置

这是一个 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会让这更容易。

于 2009-05-08T18:21:05.907 回答
6

C# 中的指针。

它们可用于就地字符串操作。这是一个不安全的特性,因此 unsafe 关键字用于标记不安全代码的区域。还要注意如何使用 fixed 关键字来指示指向的内存是固定的并且不能被 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);

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

于 2009-07-13T11:05:00.177 回答
6

阅读完所有 9 页后,我觉得我必须指出一个不为人知的功能......

对于 .NET 1.1 也是如此,对 gzip 文件使用压缩/解压缩,必须:

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

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

于 2010-01-09T01:48:03.140 回答
6

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

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

于 2010-07-06T19:52:37.000 回答
6

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

于 2010-01-10T01:27:07.047 回答
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();
于 2009-03-12T08:46:23.027 回答
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 秒内编写它,我就不太合适了。求助于剪切/粘贴简单的代码模式,无论它们是惰性初始化还是上面显示的其他一些示例......

于 2009-12-25T21:33:48.763 回答
5

Nullable.GetValueOrDefault ?

于 2010-04-05T11:15:10.473 回答
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""!!";
于 2009-09-11T03:52:09.283 回答
5

零参数 Lambda

()=>Console.ReadLine()
于 2009-07-27T00:43:31.763 回答
5

Reflection Emit and Expression trees come to mind...

Don't miss Jeffrey Richter's CLR via C# and Jon Skeet's alt text

See here for some resources:

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

于 2008-08-26T18:51:13.473 回答
5

System.Runtime.Remoting.Proxies.RealProxy

它支持 C# 中的面向方面编程,您还可以用它做很多其他花哨的事情。

于 2008-09-16T14:43:44.000 回答
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;
}
于 2008-10-12T04:26:32.297 回答
5

我没有看到这个:

for (;;);

一样

while (true) ;
于 2009-07-30T03:57:06.083 回答
5

这不会编译:

namespace ns
{
    class Class1
    {
        Nullable<int> a;
    }
}

找不到类型或命名空间名称“Nullable”(您是否缺少 using 指令或程序集引用?) <--缺少“ using System;

namespace ns
{
    class Class1
    {
        int? a;
    }
}

会编译!(.NET 2.0)。

于 2009-09-03T03:36:51.900 回答
5

@lainMH,

在从可为空的数据库中检索值以及将值放回时,可为空的布尔值很有用。有时您想知道该字段尚未设置。

于 2008-08-25T14:21:57.183 回答
5

通用事件处理程序:

public event EventHandler<MyEventArgs> MyEvent;

这样你就不必一直声明自己的代表了,

于 2008-11-03T15:26:12.897 回答
5

我最近学到的一个是你仍然可以在一个可为空的值上调用方法......

事实证明,当你有一个可为空的值时:

decimal? MyValue = null;

你可能认为你必须在哪里写:

MyValue == null ? null : MyValue .ToString()

你可以改写:

MyValue.ToString()

我知道我可以调用 MyValue.HasValue 和 MyValue.Value...但它并没有完全点击我可以调用 ToString()。

于 2009-08-23T11:07:06.030 回答
5

我没有发现 - 将近一年 - 强类型 DataRows 包含 Is[ColumnName]Null() 方法。

例如:

Units.UnitsDataTable dataTable = new Units.UnitsDataTable();

foreach (Units.UnitsRow row in dataTable.Rows)
{
    if (row.IsPrimaryKeyNull())
        //....

    if (row.IsForeignKeyNull())
        //....
}
于 2008-11-03T16:16:07.820 回答
5

FIXED / C# 中指针的力量 - 这个话题太大了,但我只会概述一些简单的事情。

在 C 语言中,我们有加载结构的设施,比如......

struct cType{
   char type[4];
   int  size;
   char name[50];
   char email[100];
}

cType myType;
fread(file, &mType, sizeof(mType));

我们可以在“不安全”方法中使用固定关键字来读取字节数组对齐的结构。

[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(从常规流读取到字节缓冲区并将字节数组映射到结构的各个字节)

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);
}
于 2009-04-23T12:57:48.963 回答
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;
...
于 2009-07-16T05:16:29.323 回答
5

我喜欢EditorBrowsableAttribute。它使您可以控制是否在 Intellisense 中显示方法/属性。您可以将值设置为始终、高级或从不。

从 MSDN ...

评论

EditorBrowsableAttribute 是对设计者的提示,指示是否要显示属性或方法。您可以在可视化设计器或文本编辑器中使用此类型来确定用户可见的内容。例如,Visual Studio 中的 IntelliSense 引擎使用此特性来确定是否显示属性或方法。

在 Visual C# 中,您可以使用工具 | 下的隐藏高级成员设置来控制高级属性何时出现在 IntelliSense 和属性窗口中。选项 | 文本编辑器 | C#。对应的 EditorBrowsableState 是 Advanced。

于 2009-11-21T08:12:56.197 回答
5

__arglist 也是

[DllImport("msvcrt40.dll")]
public static extern int printf(string format, __arglist);

static void Main(string[] args)
{
   printf("Hello %s!\n", __arglist("Bart"));
}
于 2009-12-03T00:45:50.267 回答
5

允许使用带有大括号的空块。

你可以写这样的代码

{
    service.DoTonsOfWork(args);
}

当您想尝试没有 ausingtry... finally您已经编写过的东西时,它会很有帮助。

//using(var scope = new TransactionScope)
{
    service.DoTonsOfWork(args);
}
于 2010-03-08T22:43:57.697 回答
4

泛型和奇怪重复的模板模式确实有助于一些静态方法/属性声明。

假设您正在构建一个类层次结构:

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

如果这些静态方法基本上都做同样的事情,那么你手上就有很多重复的代码。一种解决方案是在返回值上删除类型安全性并始终返回 type 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>
{
}

这样,他们将自动获得静态方法的副本

这也可以将单例模式封装在基类中创造奇迹(我知道下面的代码不是线程安全的,它只是为了说明一点):

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()构造的编译时无法避免这种情况;但是,可以使用反射在运行时调用子类的受保护/私有无参数构造函数来实现这一点。

于 2009-08-07T22:39:32.553 回答
4

在验证用户输入时,每种原始类型的 TryParse 方法都很棒。

double doubleValue
if (!Double.TryParse(myDataRow("myColumn"), out doubleValue))
{
    // set validation error
}
于 2008-09-03T15:03:20.693 回答
4

框架功能

我不知道,但我对VisualStyleRenderer和整个System.Windows.Forms.VisualStyles-Namespace感到非常惊讶。很酷!

于 2008-11-23T17:45:14.367 回答
4

能够像这样基于泛型参数创建类型的实例

新 T();

于 2009-06-16T18:38:22.347 回答
4

一些来自我的 - 让他们随心所欲。

属性:

[assembly::InternalsVisibleTo("SomeAssembly")]

允许您将程序集中的内部方法/属性或数据暴露给另一个名为“SomeAssembly”的程序集。所有受保护/私人的东西都保持隐藏。


静态构造函数(也称为“类型构造函数”)

public MyClass
{
  public static MyClass()
  {
     // type init goes here
  }
  ......
}  

关键字internal。在很多方面都很有用。

于 2009-06-14T16:11:16.937 回答
4

Marketing events as non-serializable:

[field:NonSerializable]
public event SomeDelegate SomeEvent;
于 2009-06-22T12:29:48.727 回答
4

#region {string}和 #endregion 对非常适合对代码进行分组(大纲)。

#region Using statements
using System;
using System.IO;
using ....;
using ....;
#endregion

代码块可以压缩为单个描述文本行。也适用于函数内部。

于 2008-09-19T05:18:35.503 回答
4

我学到的一件有趣的事是框架和 C# 语言的不同部分是在不同的时间编写的,因此存在不一致。例如,框架本身违反了许多 FxCop 规则,因为在编写框架时这些规则并未全部到位。

此外,using 语句旨在界定“范围”,而不是专门用于处理资源。它是在 lock 语句之后编写的。Eric Gunnerson曾经提到过,如果 using 语句首先出现,他们可能不需要编写 lock 语句(尽管谁知道,也许他们无论如何都会有),因为 using 语句可能就足够了。

于 2008-08-24T22:10:22.963 回答
4

表达式树怎么样?它们是 LINQ 的核心并允许延迟执行:

摘自David Hayden 的博客

在 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);
于 2009-07-21T21:46:11.613 回答
4

刚刚[UnmanagedFunctionPointerAttribute(CallingConvention.CDecl)]从尝试与定义没有 __stdcall 的回调的非托管 C++ 函数库接口中学到了乐趣。

于 2008-11-03T15:42:24.097 回答
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();
}
于 2008-09-20T01:50:13.817 回答
4

InternalsVisibleToAttribute 指定通常仅在当前程序集中可见的类型对另一个程序集可见。msdn上的文章

于 2009-04-27T16:46:52.050 回答
4

如果您的 Visual Studio 工具栏中有搜索文本框,您可以键入“> of Program.cs”以打开文件 Program.cs

于 2009-06-05T20:56:00.313 回答
4

这对于数据库应用程序开发人员来说可能是非常基础的,但我花了一段时间才意识到 null 与 DBNull.value 不同。

当您想查看数据库记录中的值是否为空时,您必须使用 DBNull.value。

于 2008-10-21T19:08:37.363 回答
4

您可以组合protectedandinternal访问器,使其在同一个程序集中公开,但在不同程序集中受到保护。这可以用于字段、属性、方法甚至常量。

于 2012-02-23T12:34:19.723 回答
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"
};
于 2010-02-11T10:37:59.893 回答
4

将枚举值转换为字符串值

鉴于枚举

enum Country
{
    UnitedKingdom, 
    UnitedStates,
    UnitedArabEmirates,
}

使用它:

public static void PrintEnumAsString( Country country )
{
    Console.Writeline( country.ToString() );
}

将枚举值的名称打印为字符串,例如“UnitedKingdom”

于 2009-11-25T17:16:48.400 回答
4

对象初始化器中的集合初始化器:

MailMessage mail = new MailMessage {
   To = { new MailAddress("a@example.com"), new MailAddress("b@example.com") },
   Subject = "Password Recovery"
};

您可以在单个表达式中初始化整个树。

于 2010-02-09T19:05:23.790 回答
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 

{...}
于 2009-06-30T07:11:12.670 回答
4

这在标准中已经解释了很多。对于任何初学者和专家来说,这都是一本好书,读起来很多,但它是官方标准,并且充满了有趣的细节。

一旦您完全理解了 C#,就该进一步了解公共语言基础结构的基础知识了。C# 的体系结构和基础。

我遇到过各种各样的程序员,他们不知道对象和 ValueType 之间的区别,除了它们的相关限制。

熟悉这两个文件,你永远不会成为那个人。

于 2009-08-05T17:01:19.033 回答
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
    }
}

干杯,弗洛里安

于 2009-10-26T16:45:31.897 回答
4

我只想提一下(因为 OP 提到 where T : struct)C# 编译器的问题之一是

where T : Enum

不会编译。它抛出错误“约束不能是特殊类'System.Enum'”。

于 2010-02-02T22:12:39.037 回答
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);
        }
    }
}

当程序退出时,“静态析构函数”被调用。

于 2010-04-05T03:58:57.897 回答
4

我不宽恕它,但我很惊讶goto仍然围绕着鸭子来袭的弹丸

于 2010-06-22T19:57:59.953 回答
4
  • 附加 到一个类型,使其可以为空,例如: int?
  • "c:\dir" 而不是@"C:\dir"
于 2010-01-07T15:57:15.387 回答
4

Visual Studio 最有用的功能之一是“制作对象 ID”。它会生成一个 id 并“附加”到对象,因此无论您在哪里查看对象,您都会看到 id(无论线程如何)。

调试时右键单击变量工具提示,就可以了。它也适用于 watch/autos/locals 变量。

于 2010-03-11T15:01:42.510 回答
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; }
}

这适用于字典支持的任何内容。

于 2008-11-15T07:14:26.467 回答
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,
    });
}
于 2008-08-28T14:49:03.490 回答
3

上下文绑定对象

与其说是 C#,不如说是 .NET。这是实现 DI 的另一种方式,尽管它可能很辛苦。而且你必须从它继承,这可能会令人反感。

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

当我使用自定义日志记录属性装饰类/方法时,我使用它来添加日志记录。

于 2008-10-09T20:37:13.477 回答
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;
于 2009-08-14T20:53:32.227 回答
3

ThreadStaticAttribute 是我的最爱。此外,NonSerializableAttribute 很有用。(你能告诉我使用远程处理做了很多服务器工作吗?)

于 2008-11-01T19:48:28.017 回答
3
double dSqrd = Math.Pow(d,2.0); 

比更准确

double dSqrd = d * d; // Here we can lose precision
于 2008-10-13T22:29:09.880 回答
3

参考带有永久链接的帖子“ 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

我不确定这是否是一个未知功能!

于 2010-04-08T19:30:55.320 回答
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

于 2009-09-10T11:21:28.523 回答
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();
        }
    }
}
于 2009-02-03T18:42:13.857 回答
3

下面的不是隐藏的,而是相当隐含的。不知道有没有像下面这样的示例在这里发布过,也看不出有什么好处(可能没有),但我会尽量展示一个“奇怪”的代码。以下示例for通过 C# 中的仿函数(委托/匿名委托 [lambdas])和闭包模拟语句。其他流程语句,如,if和也是 模拟的,但我不确定(也许,我太懒了:))。我已经压缩了示例源代码以使其更清晰。if/elsewhiledo/whleswitch

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

如果我没记错的话,这种方法与函数式编程实践相当相关。我对吗?

于 2009-10-29T23:44:23.133 回答
3

如果您尝试从项目列表中创建逗号分隔的字符串:

string[] itemList = { "Example 1", "Example 2", "Example 3" };
CommaDelimitedStringCollection commaStr = new CommaDelimitedStringCollection();
commaStr.AddRange(itemList);
//outputs Example 1,Example 2,Example 3

这里的另一个例子。

于 2009-07-23T19:26:07.540 回答
3

好吧...不要用它,但是很多人不知道C#支持邪恶的goto :)

static void Example()
{
    int i = 0;
top:
    Console.WriteLine(i.ToString());
    if (i == 0)
    {
        i++;
        goto top;
    }
}
于 2009-05-22T19:28:26.923 回答
3

当与 .NET 3.5 中的语句 lambda 一起使用时,绝对是 Func<> 类型。这些允许可定制的功能,并且可以极大地帮助提供用户可定制的对象,而无需对它们进行子类化或诉诸某些有限的系统,例如跟踪列出用户想要监视的按钮或键的变量。此外,它们可以像常规方法一样被调用,并且可以像变量一样被赋值。我能想到的唯一缺点是您仅限于 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 函数来快速事件引发器的例子,而无需代理的麻烦。编辑:想到另一个。可空值!C# 最接近可选参数的东西。

于 2009-06-04T08:41:48.907 回答
3

不知道这本身是否是一个秘密,但我喜欢 System.Linq 中添加的 Enumerable(添加到 IEnumerable)类。

http://msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx

虽然 yield 关键字已经列出。迭代器块真是太神奇了。我用它们来构建列表,这些列表将被测试以查看它们是否是互质的。它基本上允许您通过一个一个一个返回值并随时停止的函数。

哦,当您无法再优化时,我差点忘记了世界上最好的课程。后台工作者!!!!

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

于 2010-01-13T09:31:52.353 回答
3

最近我了解了 String.Join 方法。在构建像列这样的字符串以供查询选择时非常有用。

于 2010-06-09T14:39:44.047 回答
3

“TODO”属性和任务列表

//TODO: [something] 

将其添加到您的代码中(间距很重要)会在您的任务列表中抛出一个项目,双击该项目会将您跳转到代码中的适当位置。

于 2009-12-29T21:41:35.003 回答
3

我不知道可以帮助避免使用方法重载的通用方法。下面是打印 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);
        }
    }
于 2010-01-05T11:51:22.167 回答
2

上一页属性:

“System.Web.UI.Page 表示将控制权转移到当前页面的页面。”

这是非常有用的。

于 2008-09-02T02:10:06.660 回答
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/invokes,具有专门用于互操作的库,以及用于互操作的语言功能,例如pin_ptr。它允许托管代码和本机代码在同一个二进制文件中共存。

在 C# 方面,您只需像调用任何其他 .NET 二进制文件一样调用 DLL。

于 2009-05-08T17:43:21.533 回答
2

我必须承认,我不确定这是否比正常的 ASP.NET 中继器 onItemDatabound 转换代码的性能更好或更差,但无论如何这是我的 5 美分。

MyObject obj = e.Item.DataItem as MyObject;
if(obj != null)
{
  //Do work
}
于 2008-08-18T17:06:41.957 回答
2

Before lambda comes into play, it's anonymous delegate. That could be used for blanket code similar to Ruby's blockgiven. I haven't tested how lambda works though because I want to stick with .NET 2.0 so far.

For example when you want to make sure you remember to close your HTML tags:

MyHtmlWriter writer=new MyHtmlWriter();
writer.writeTag("html", 
  delegate ()
  { 
    writer.writeTag("head", 
       delegate() 
       { 
           writer.writeTag("title"...);
       }
    )
  })

I am sure if lambda is an option, that could yield much cleaner code :)

于 2008-09-19T16:26:29.023 回答
2

我认为如果您必须使用可为空的类型,最好使用 Nullable<.T> 而不是问号表示法。这使得魔法正在发生的事情变得非常明显。不知道为什么有人会想使用 Nullable<.bool> 。

在 VB.NET Web 服务中,参数可能不会通过(因为合作伙伴的请求不一致或不可靠),但必须通过针对建议类型的验证(“如果是搜索请求”的布尔值)。把它归结为“管理层的另一个要求”......

...是的,我知道有些人认为这不是做这些事情的正确方法,但是IsSearchRequest As Nullable(Of Boolean)让我那天晚上失去了理智!

于 2008-08-18T00:10:35.893 回答
2

@罗比火箭裤

“但我的直觉告诉我,这会将最多两种类型转换操作减少到最多一种。”

如果您按照示例 1 中的建议进行强制转换(使用 is & 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)
{
}

对比

MyClass c = obj as MyClass;

if (c != null)
{
}

您可以看到哪个更快、更简洁、更清晰。

于 2008-09-05T09:14:04.713 回答
2

BCL 中的一些并发实用程序可能符合隐藏功能。

诸如 System.Threading.Monitor 之类的东西由 lock 关键字在内部使用;显然,在 C# 中 lock 关键字是可取的,但有时需要知道事情是如何在较低级别完成的;我必须锁定 C++/CLI,所以我用调用 Monitor.Enter() 和 Monitor.Exit() 封装了一段代码。

于 2008-09-19T14:39:16.503 回答
2

在包含转义字符的字符串之前使用 @。基本上,当使用物理路径在字符串变量中分配时,每个人都使用“\”,其中字符串中存在转义字符。

例如字符串 strPath="D:\websites\web1\images\";

但是可以在字符串值之前使用 @ 忽略转义字符。

例如字符串 strPath=@"D:\websites\web1\images\";

于 2009-10-20T10:04:34.167 回答
2

看到上面提到了 List.ForEach;2.0 引入了一系列基于谓词的集合操作 - Find、FindAll、Exists 等。再加上匿名委托,您几乎可以实现 3.5 的 lambda 表达式的简单性。

于 2008-09-09T03:30:49.463 回答
2

大多数P/Invoke的东西有点奇怪。

属性示例:

[DllImport ("gdi32.dll")] 
[return : MarshalAs(UnmanagedType.I4)]
[StructLayout(LayoutKind.Sequential)]
于 2010-03-02T05:16:54.683 回答
2

谨慎使用时,选举是如此强大。我在电子邮件模板系统中使用它。模板管理器将被传递一个对象,并且 html 模板将具有引用属性的嵌入字段,这些属性可以使用反射从传递的对象中检索出来。效果很好。

于 2009-06-03T15:37:49.650 回答
2

另一种通过 yield 获取 IEnumerable 而不显式创建 IEnumerable 对象的方法

public IEnumerable<Request> SomeMethod(IEnumerable<Request> requests)
{
    foreach (Request request in requests)
       yield return DoSomthing(request);
}
于 2010-01-26T19:16:16.897 回答
2

不确定微软是否会喜欢这个问题,尤其是有这么多回复。我敢肯定,我曾经听过一位微软负责人说:

隐藏的功能是浪费的功能

......或类似的东西。

于 2009-09-12T21:26:06.890 回答
2

这个使用 Delegate.CreateDelegate 调用私有方法的技巧非常巧妙。

var subject = new Subject();
var doSomething = (Func<String, String>)
    Delegate.CreateDelegate(typeof(Func<String, String>), subject, "DoSomething");
Console.WriteLine(doSomething("Hello Freggles"));

这是一个有用的上下文

于 2010-02-16T09:58:48.280 回答
1

以下是有关如何使用 #Region 指令来记录代码的提示。

于 2008-11-18T10:54:30.593 回答
1

如果要阻止垃圾收集器运行对象的终结器,只需使用GC.SuppressFinalize(object);. 以类似的方式,GC.KeepAlive(object);将阻止垃圾收集器通过引用它来收集该对象。不是很常用,至少在我的经验中,但很高兴知道以防万一。

于 2009-06-03T14:53:50.137 回答
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>
于 2010-05-16T09:55:53.540 回答
1

如果允许第 3 方扩展,那么C5Microsoft CCR(请参阅此博客文章以获得快速介绍)是必须了解的。

C5 补充了 .Net 有点缺乏的集合库(不是 Set???),CCR 使并发编程更容易(我听说它应该与 Parallel Extensions 合并)。

于 2008-09-19T19:20:30.743 回答
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));

有趣的是注意到由于某种原因需要的最后一个演员表。错误还是设计?

于 2008-09-23T07:45:27.323 回答
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 
于 2009-03-31T04:18:58.253 回答
1

当您需要(a)在对象之间就事件的发生进行同步通信时,有一个称为ISynchronizeInvoke的专用接口。

引用 MSDN 文章(链接):

实现此接口的对象可以接收事件发生的通知,并且可以响应有关事件的查询。通过这种方式,客户端可以确保在提交取决于第一个完成的后续请求之前已经处理了一个请求。

这是一个通用包装器:

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));
}
于 2009-08-05T17:20:36.187 回答
1

异常过滤器。所以“隐藏”你甚至不能在没有编译后补丁的情况下使用它们(至少从 C# 中);)

于 2009-07-17T14:29:23.230 回答
0

我不知道这是否是一个隐藏功能(“”)。任何字符串函数。

于 2010-02-19T03:54:47.300 回答