Ser*_*gel 1475 c# hidden-features
where T : struct
Run Code Online (Sandbox Code Playgroud)
我们C#开发人员都知道C#的基础知识.我的意思是声明,条件,循环,运算符等.
我们中的一些人甚至掌握了Generics,匿名类型,lambdas,LINQ等......
但是C#粉丝,瘾君子,专家几乎都不知道C#最隐藏的功能或技巧是什么?
yield由迈克尔·葡萄汁var由迈克尔·葡萄汁using()kokos的声明readonly由kokosas由迈克·斯通as/ is由埃德Swangrenas/ is(改进)由Rocketpantsdefault由deathofratsglobal::通过pzycomanusing()由块AlexCusevolatile作者:JakubŠturcextern alias作者:JakubŠturcDefaultValueAttribute由迈克尔·葡萄汁ObsoleteAttribute作者DannySmurfDebuggerDisplayAttribute由斯图DebuggerBrowsable并DebuggerStepThrough通过bdukesThreadStaticAttribute通过marxidadFlagsAttribute作者:Martin ClarkeConditionalAttribute作者:AndrewBurns??(合并空值)运算符由kokoswhere T:new作者:LarsMæhlumenum价值由lfoustevent马克西德的经营者?:)checked和Binoj Antony的unchecked运营商implicit and explicitFlory的运营商__makeref __reftype __refvalue由Judah Himango提供partialJon Erickson的方法DEBUGRobert Durgin的预处理器指令__arglist作者:Zac BowlingTransactionScope由KiwiBastardDependantTransaction由KiwiBastardNullable<T>作者:IainMHMutex通过DiagoSystem.IO.Path通过ageektrappedWeakReference作者:Juan ManuelString.IsNullOrEmpty()KiwiBastard的方法List.ForEach()KiwiBastard的方法BeginInvoke(),EndInvoke()通过以下方法威尔院长Nullable<T>.HasValue并Nullable<T>.Value通过性能RismoGetValueOrDefaultJohn Sheehan的方法age*_*ped 752
这不是C#本身,但我没有看到任何人真正使用System.IO.Path.Combine()它们应该的程度.事实上,整个Path类非常有用,但没有人使用它!
我愿意打赌每个生产应用程序都有以下代码,即使它不应该:
string path = dir + "\\" + fileName;
Run Code Online (Sandbox Code Playgroud)
cha*_*rit 585
lambdas和类型推理被低估了.Lambdas可以有多个语句,它们会自动兼容为兼容的委托对象(只需确保签名匹配),如下所示:
Console.CancelKeyPress +=
(sender, e) => {
Console.WriteLine("CTRL+C detected!\n");
e.Cancel = true;
};
Run Code Online (Sandbox Code Playgroud)
请注意,我没有new CancellationEventHandler也不必指定类型,sender并且e它们可以从事件中推断出来.这就是为什么编写整体不那么麻烦,delegate (blah blah)这也需要您指定参数类型.
Lambdas不需要返回任何内容,类型推断在这样的上下文中非常强大.
顺便说一下,你可以随时返回Lambdas,它们在函数式编程意义上使Lambdas成为可能.例如,这是一个lambda,它使lambda处理Button.Click事件:
Func<int, int, EventHandler> makeHandler =
(dx, dy) => (sender, e) => {
var btn = (Button) sender;
btn.Top += dy;
btn.Left += dx;
};
btnUp.Click += makeHandler(0, -1);
btnDown.Click += makeHandler(0, 1);
btnLeft.Click += makeHandler(-1, 0);
btnRight.Click += makeHandler(1, 0);
Run Code Online (Sandbox Code Playgroud)
注意链接: (dx, dy) => (sender, e) =>
这就是为什么我很高兴参加函数式编程课程:-)
除了C中的指针,我认为这是你应该学习的另一个基本的东西:-)
jfs*_*jfs 528
来自Rick Strahl:
你可以链?运算符,以便您可以进行一堆空比较.
string result = value1 ?? value2 ?? value3 ?? String.Empty;
Run Code Online (Sandbox Code Playgroud)
Bla*_*erX 455
别名仿制药:
using ASimpleName = Dictionary<string, Dictionary<string, List<string>>>;
Run Code Online (Sandbox Code Playgroud)
它允许你使用ASimpleName,而不是Dictionary<string, Dictionary<string, List<string>>>.
当你在很多地方使用相同的通用大而复杂的东西时使用它.
jfs*_*jfs 438
从CLR到C#:
规范化字符串时,强烈建议您使用ToUpperInvariant而不是ToLowerInvariant,因为Microsoft已优化用于执行大写比较的代码.
我记得有一次我的同事在比较之前总是把字符串换成大写字母.我一直想知道为什么他这样做,因为我觉得首先转换为小写更为"自然".现在读完这本书后,我知道为什么.
小智 409
我最喜欢的技巧是使用null coalesce运算符和括号来为我自动实例化集合.
private IList<Foo> _foo;
public IList<Foo> ListOfFoo
{ get { return _foo ?? (_foo = new List<Foo>()); } }
Run Code Online (Sandbox Code Playgroud)
and*_*nil 314
避免检查null事件处理程序
在声明时向事件添加一个空委托,禁止在调用它之前始终检查该事件是否真棒.例:
public delegate void MyClickHandler(object sender, string myValue);
public event MyClickHandler Click = delegate {}; // add empty delegate!
Run Code Online (Sandbox Code Playgroud)
让你这样做
public void DoSomething()
{
Click(this, "foo");
}
Run Code Online (Sandbox Code Playgroud)
而不是这个
public void DoSomething()
{
// Unnecessary!
MyClickHandler click = Click;
if (click != null) // Unnecessary!
{
click(this, "foo");
}
}
Run Code Online (Sandbox Code Playgroud)
另请参阅此相关讨论和Eric Lippert关于此主题的博客文章(以及可能的缺点).
Kei*_*ith 305
其他一切,加上
1)隐式泛型(为什么只有方法而不是类?)
void GenericMethod<T>( T input ) { ... }
//Infer type, so
GenericMethod<int>(23); //You don't need the <>.
GenericMethod(23); //Is enough.
Run Code Online (Sandbox Code Playgroud)
2)带有一个参数的简单lambda:
x => x.ToString() //simplify so many calls
Run Code Online (Sandbox Code Playgroud)
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 };
Run Code Online (Sandbox Code Playgroud)
另一个:
4)自动属性可以有不同的范围:
public int MyId { get; private set; }
Run Code Online (Sandbox Code Playgroud)
谢谢@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();
Run Code Online (Sandbox Code Playgroud)
Mik*_*one 286
很长一段时间我都不知道"as"关键字.
MyClass myObject = (MyClass) obj;
Run Code Online (Sandbox Code Playgroud)
VS
MyClass myObject = obj as MyClass;
Run Code Online (Sandbox Code Playgroud)
如果obj不是MyClass,则第二个将返回null,而不是抛出类强制转换异常.
lom*_*axx 262
我喜欢的两件事是自动属性,因此您可以进一步折叠代码:
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
Run Code Online (Sandbox Code Playgroud)
变
public string Name { get; set;}
Run Code Online (Sandbox Code Playgroud)
对象初始值设定项:
Employee emp = new Employee();
emp.Name = "John Smith";
emp.StartDate = DateTime.Now();
Run Code Online (Sandbox Code Playgroud)
变
Employee emp = new Employee {Name="John Smith", StartDate=DateTime.Now()}
Run Code Online (Sandbox Code Playgroud)
小智 255
泛型类型中的'default'关键字:
T t = default(T);
Run Code Online (Sandbox Code Playgroud)
如果T是引用类型,则返回'null';如果是int,则返回0;如果是布尔值,则返回false,等等.
Stu*_*Stu 226
一般属性,但最重要的是DebuggerDisplay.为您节省数年.
lom*_*axx 221
@告诉编译器忽略字符串中的任何转义字符.
只是想澄清一下......它没有告诉它忽略转义字符,它实际上告诉编译器将字符串解释为文字.
如果你有
string s = @"cat
dog
fish"
Run Code Online (Sandbox Code Playgroud)
它实际上会打印出来(注意它甚至包括用于缩进的空格):
cat
dog
fish
Run Code Online (Sandbox Code Playgroud)
Jas*_*son 220
我认为C#(.NET 3.5)最不受欢迎和鲜为人知的功能之一是表达式树,特别是与Generics和Lambdas结合使用时.这是一种API创建方法,像NInject和Moq这样的新库正在使用.
例如,假设我想要使用API注册方法,并且API需要获取方法名称
鉴于此类:
public class MyClass
{
public void SomeMethod() { /* Do Something */ }
}
Run Code Online (Sandbox Code Playgroud)
之前,通常会看到开发人员使用字符串和类型(或其他主要基于字符串的方式)执行此操作:
RegisterMethod(typeof(MyClass), "SomeMethod");
Run Code Online (Sandbox Code Playgroud)
嗯,这很糟糕,因为缺乏强力打字.如果我重命名"SomeMethod"怎么办?现在,在3.5中,我可以以强类型的方式执行此操作:
RegisterMethod<MyClass>(cl => cl.SomeMethod());
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这是我现在爱上Lambdas和Expression Trees的一个重要原因.
Mic*_*tum 209
我会想到" 屈服 ".像[DefaultValue()]这样的一些属性也是我的最爱.
" var "关键字更为人所知,但您也可以在.NET 2.0应用程序中使用它(只要您使用.NET 3.5编译器并将其设置为输出2.0代码)似乎不是很清楚好.
编辑:kokos,谢谢你指出?? 运算符,这确实非常有用.因为它有点难以谷歌(因为??只是被忽略),这里是该运算符的MSDN文档页面:?? 运算符(C#参考)
Bra*_*ker 198
我倾向于发现大多数C#开发人员都不知道'可空'类型.基本上,可以具有空值的基元.
double? num1 = null;
double num2 = num1 ?? -100;
Run Code Online (Sandbox Code Playgroud)
将可空双精度数num1设置为null,然后将常规双精度数num2设置为num1或-100(如果num1为null).
http://msdn.microsoft.com/en-us/library/1t3y8s4s(VS.80).aspx
关于Nullable类型还有一件事:
DateTime? tmp = new DateTime();
tmp = null;
return tmp.ToString();
Run Code Online (Sandbox Code Playgroud)
它返回String.Empty.查看此链接了解更多详情
Jud*_*ngo 193
以下是一些有趣的隐藏C#功能,以未记录的C#关键字的形式:
__makeref
__reftype
__refvalue
__arglist
Run Code Online (Sandbox Code Playgroud)
这些是未记录的C#关键字(甚至Visual Studio识别它们!),这些关键字是为了在泛型之前更有效的装箱/拆箱而添加的.它们与System.TypedReference结构协同工作.
还有__arglist,用于可变长度参数列表.
人们不太了解的一件事是System.WeakReference - 一个非常有用的类,它跟踪一个对象,但仍然允许垃圾收集器收集它.
最有用的"隐藏"功能是yield return关键字.它并没有真正隐藏,但很多人都不知道.LINQ建立于此之上; 它允许通过在引擎盖下生成状态机来执行延迟执行的查询.Raymond Chen最近发布了有关内部细节的细节.
Zer*_*nce 185
联合(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;
}
Run Code Online (Sandbox Code Playgroud)
您可以通过操作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);
}
Run Code Online (Sandbox Code Playgroud)
输出:
2147483647
FF FF FF 7F
65535
Run Code Online (Sandbox Code Playgroud)
只需使用System.Runtime.InteropServices添加;
Mar*_*ade 176
使用@作为关键字的变量名.
var @object = new object();
var @string = "";
var @if = IpsoFacto();
Run Code Online (Sandbox Code Playgroud)
Jan*_*ter 168
如果要在不调用任何finally块或终结器的情况下退出程序,请使用FailFast:
Environment.FailFast()
Run Code Online (Sandbox Code Playgroud)
den*_*ips 153
从方法返回匿名类型并访问成员而不进行反射.
// Useful? probably not.
private void foo()
{
var user = AnonCast(GetUserTuple(), new { Name = default(string), Badges = default(int) });
Console.WriteLine("Name: {0} Badges: {1}", user.Name, user.Badges);
}
object GetUserTuple()
{
return new { Name = "dp", Badges = 5 };
}
// Using the magic of Type Inference...
static T AnonCast<T>(object obj, T t)
{
return (T) obj;
}
Run Code Online (Sandbox Code Playgroud)
Pat*_*ick 146
这是正则表达式和文件路径的一个有用的:
"c:\\program files\\oldway"
@"c:\program file\newway"
Run Code Online (Sandbox Code Playgroud)
@告诉编译器忽略字符串中的任何转义字符.
Dmi*_*ruk 142
混入.基本上,如果要向多个类添加一个功能,但不能为所有类使用一个基类,请让每个类实现一个接口(没有成员).然后,为接口编写扩展方法,即
public static DeepCopy(this IPrototype p) { ... }
Run Code Online (Sandbox Code Playgroud)
当然,牺牲一些清晰度.但它的确有效!
Mic*_*tum 131
不知道为什么有人会想要使用Nullable <bool>.:-)
真,假,FileNotFound?
Bra*_*son 117
这个不是"隐藏"的,因为它被误解了.
很多注意力都集中在算法"map","reduce"和"filter"上.大多数人没有意识到的是,.NET 3.5添加了所有这三种算法,但是基于它们是LINQ的一部分,它给了它们非常的SQL-ish名称.
"map"=>选择
将数据从一种形式转换为另一种形式"reduce"=> Aggregate
Aggregates值为单个结果"filter"=> Where
根据条件过滤数据
使用LINQ对过去采用迭代和条件的集合进行内联工作的能力非常有价值.值得了解所有LINQ扩展方法如何帮助您的代码更加紧凑和可维护.
nim*_*ish 115
Environment.NewLine
Run Code Online (Sandbox Code Playgroud)
用于系统独立的换行符.
Por*_*man 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"
Run Code Online (Sandbox Code Playgroud)
kok*_*kos 104
Dog*_*ang 103
@Ed,我对发布这个有点保持沉默,因为它只不过是挑剔.但是,我会在您的代码示例中指出:
MyClass c;
if (obj is MyClass)
c = obj as MyClass
Run Code Online (Sandbox Code Playgroud)
如果您打算使用'is',为什么要使用'as'进行安全投射?如果你已经确定obj确实是MyClass,那么沼泽标准演员:
c = (MyClass)obj
Run Code Online (Sandbox Code Playgroud)
......永远不会失败.
同样,你可以说:
MyClass c = obj as MyClass;
if(c != null)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我不太了解.NET的内部结构,但我的直觉告诉我,这将最多将两个类型转换操作减少到最多一个.无论如何,它几乎不可能破坏处理银行; 就个人而言,我认为后一种形式看起来也更清洁.
Jas*_*onS 98
也许不是一种先进的技术,但我总是看到让我疯狂的一种技术:
if (x == 1)
{
x = 2;
}
else
{
x = 3;
}
Run Code Online (Sandbox Code Playgroud)
可以浓缩为:
x = (x==1) ? 2 : 3;
Run Code Online (Sandbox Code Playgroud)
Ral*_*veo 94
许多人没有意识到他们可以使用OrdinalIgnoreCase来比较字符串,而不必使用someString.ToUpper().这消除了额外的字符串分配开销.
if( myString.ToUpper() == theirString.ToUpper() ){ ... }
Run Code Online (Sandbox Code Playgroud)
变
if( myString.Equals( theirString, StringComparison.OrdinalIgnoreCase ) ){ ... }
Run Code Online (Sandbox Code Playgroud)
Cri*_*rdo 80
刚刚学习,匿名类型可以从变量名称推断属性名称:
string hello = "world";
var o = new { hello };
Console.WriteLine(o.hello);
Run Code Online (Sandbox Code Playgroud)
Nic*_*rdi 75
老实说,定义中的专家应该知道这些东西.但要回答你的问题:内置类型表(C#参考)
标记数字的编译器广为人知:
Decimal = M
Float = F
Double = D
// for example
double d = 30D;
Run Code Online (Sandbox Code Playgroud)
然而,这些更加模糊:
Long = L
Unsigned Long = UL
Unsigned Int = U
Run Code Online (Sandbox Code Playgroud)
ljs*_*ljs 75
我喜欢在列表中查找内容: -
bool basketContainsFruit(string fruit) {
return new[] { "apple", "orange", "banana", "pear" }.Contains(fruit);
}
Run Code Online (Sandbox Code Playgroud)
而不是:-
bool basketContainsFruit(string fruit) {
return fruit == "apple" || fruit == "orange" || fruit == "banana" ||
fruit == "pear";
}
Run Code Online (Sandbox Code Playgroud)
在实践中没有那么多,但是将项目与搜索主题相匹配的想法可能非常有用+简洁.
DAC*_*DAC 73
InternalsVisibleTo属性是一个众所周知的属性,但在某些情况下可以增加方便.它基本上允许另一个程序集能够访问定义程序集的"内部"元素.
jcr*_*ruz 72
这是C#4.0中字符串类的新方法:
String.IsNullOrWhiteSpace(String value)
Run Code Online (Sandbox Code Playgroud)
是时候了.
小智 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);
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅" C#中的隐式方法组转换 ".
Jam*_*rue 68
还有更多,但这是我头脑中最明显的三个......
Wyz*_*fen 67
Dictionary.TryGetValue(K键,输出V值)
作为一个支票和一个进入.而不是;
if(dictionary.ContainsKey(key))
{
value = dictionary[key];
...
}
Run Code Online (Sandbox Code Playgroud)
你可以做;
if(dictionary.TryGetValue(key, out value))
{ ... }
Run Code Online (Sandbox Code Playgroud)
并且已设置该值.
Chr*_*ann 66
根据数字是正数,负数还是零,对数字应用不同的格式.
string s = string.Format("{0:positive;negative;zero}", i);
Run Code Online (Sandbox Code Playgroud)
例如
string format = "000;-#;(0)";
string pos = 1.ToString(format); // 001
string neg = (-1).ToString(format); // -1
string zer = 0.ToString(format); // (0)
Run Code Online (Sandbox Code Playgroud)
Mar*_*ade 64
事件实际上是代理,任何委托对象都可以附加多个函数,并分别使用+ =和 - =运算符从中分离.
也可以使用add/remove控制事件,类似于get/set,除非在使用+ =和 - =时调用它们:
public event EventHandler SelectiveEvent(object sender, EventArgs args)
{ add
{ if (value.Target == null) throw new Exception("No static handlers!");
_SelectiveEvent += value;
}
remove
{ _SelectiveEvent -= value;
}
} EventHandler _SelectiveEvent;
Run Code Online (Sandbox Code Playgroud)
Mik*_*Two 57
更多的运行时功能,但我最近了解到有两个垃圾收集器.工作站gc和服务器gc.Workstation是客户端版本的Windows的默认设置,但服务器在多核计算机上要快得多.
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
Run Code Online (Sandbox Code Playgroud)
小心.服务器gc需要更多内存.
Gro*_*kys 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;
}
Run Code Online (Sandbox Code Playgroud)
Bin*_*ony 55
其他未充分利用运营商checked和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
Run Code Online (Sandbox Code Playgroud)
Jos*_*shL 55
用"扔;" 而不是"抛出前"; 保留堆栈跟踪
如果在不添加其他信息的情况下重新抛出异常,请使用"throw"而不是"throw ex".catch块中的空"throw"语句将发出特定的IL,它会在保留原始堆栈跟踪的同时重新抛出异常."throw ex"将堆栈跟踪丢失到异常的原始源.
Him*_*dri 48
我只是想在没有评论的情况下复制该代码.因此,诀窍是只需按Alt键,然后突出显示您喜欢的矩形(例如下面).
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
//if (e.CommandName == "sel")
//{
// lblCat.Text = e.CommandArgument.ToString();
//}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,如果我想选择:
e.CommandName == "sel"
lblCat.Text = e.Comman
Run Code Online (Sandbox Code Playgroud)
然后我按下ALt键并选择矩形,无需取消注释.
看一下这个.
Kon*_*man 47
@David在达科他州:
Console.WriteLine( "-".PadRight( 21, '-' ) );
Run Code Online (Sandbox Code Playgroud)
我曾经这样做,直到我发现String类有一个构造函数,允许你以更干净的方式做同样的事情:
new String('-',22);
Run Code Online (Sandbox Code Playgroud)
小智 45
我喜欢的几件事:
- 如果你创建一个类似的界面
public interface SomeObject<T> where T : SomeObject<T>, new()
Run Code Online (Sandbox Code Playgroud)
你强制从这个接口继承的任何东西都包含一个无参数的构造函数.这对我碰到的几件事非常有用.
- 使用匿名类型动态创建有用的对象:
var myAwesomeObject = new {Name="Foo", Size=10};
Run Code Online (Sandbox Code Playgroud)
- 最后,许多Java开发人员熟悉如下语法:
public synchronized void MySynchronizedMethod(){}
Run Code Online (Sandbox Code Playgroud)
但是,在C#中,这不是有效的语法.解决方法是方法属性:
[MethodImpl(MethodImplOptions.Synchronized)]
public void MySynchronizedMethod(){}
Run Code Online (Sandbox Code Playgroud)
Tim*_*vis 45
params关键字,即
public void DoSomething(params string[] theStrings)
{
foreach(string s in theStrings)
{
// Something with the Strings…
}
}
Run Code Online (Sandbox Code Playgroud)
叫做像
DoSomething(“The”, “cat”, “sat”, “on”, “the” ,”mat”);
Run Code Online (Sandbox Code Playgroud)
and*_*nil 44
Foreach使用Duck Typing
从Krzysztof Cwalinas的博客上解释,或无耻地偷窃.比任何事都更有趣的琐事.
对于支持foreach的对象,您不必实现IEnumerable.即,这不是约束,编译器不会检查它.检查的是那个
例如,
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!");
}
Run Code Online (Sandbox Code Playgroud)
cor*_*ore 42
静态构造函数.
实例:
public class Example
{
static Example()
{
// Code to execute during type initialization
}
public Example()
{
// Code to execute during object initialization
}
}
Run Code Online (Sandbox Code Playgroud)
静态类:
public static class Example
{
static Example()
{
// Code to execute during type initialization
}
}
Run Code Online (Sandbox Code Playgroud)
MSDN 说:
静态构造函数用于初始化任何静态数据,或执行仅需执行一次的特定操作.在创建第一个实例或引用任何静态成员之前自动调用它.
例如:
public class MyWebService
{
public static DateTime StartTime;
static MyWebService()
{
MyWebService.StartTime = DateTime.Now;
}
public TimeSpan Uptime
{
get { return DateTime.Now - MyWebService.StartTime; }
}
}
Run Code Online (Sandbox Code Playgroud)
但是,您也可以轻松地做到:
public class MyWebService
{
public static DateTime StartTime = DateTime.Now;
public TimeSpan Uptime
{
get { return DateTime.Now - MyWebService.StartTime; }
}
}
Run Code Online (Sandbox Code Playgroud)
因此,当您确实需要使用静态构造函数时,您将很难找到任何实例.
MSDN提供有关静态构造函数的有用说明:
静态构造函数不接受访问修饰符或具有参数.
在创建第一个实例
或引用任何静态成员之前,会自动调用静态构造函数来初始化类.无法直接调用静态构造函数.
用户无法控制何时在程序中执行静态构造函数.
静态构造函数的典型用法是当类使用日志文件并且构造函数用于将
条目写入此文件时.
当构造函数
可以调用LoadLibrary方法时,静态构造函数在为非托管代码创建包装类时也很有用.如果静态构造函数抛出异常,则运行时将不会
再次调用它,并且该类型将
在运行程序的应用程序域的生命周期内保持未初始化状态.
最重要的注意事项是,如果静态构造函数中发生错误,TypeIntializationException则抛出a并且无法向下钻取到有问题的代码行.相反,你必须检查TypeInitializationException的InnerException成员,这是具体原因.
bdu*_*kes 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; }
}
Run Code Online (Sandbox Code Playgroud)
Shi*_*hah 39
C#+ CLR:
Thread.MemoryBarrier:大多数人都不会使用它,MSDN上有一些不准确的信息.但是,如果您知道错综复杂,那么您可以进行漂亮的无锁同步.
volatile, Thread.VolatileRead, Thread.VolatileWrite:很少有人能够使用这些,甚至更少的人了解他们避免和介绍的所有风险:).
ThreadStatic变量:过去几年中只有一种情况我发现ThreadStatic变量绝对是神派并且不可或缺.例如,当你想为整个调用链做某事时,它们非常有用.
fixed 关键字:当你想要像C++一样快地访问大型数组的元素时,这是一个隐藏的武器(默认情况下,C#强制执行绑定检查,这会降低速度).
default(typeName)关键字也可以在泛型类之外使用.创建struct的空副本很有用.
我使用的一个方便的功能是DataRow[columnName].ToString()始终返回非空值.如果数据库中的值为NULL,则为空字符串.
当您希望开发人员注意时,使用Debugger对象会自动中断,即使他/她没有启用异常时自动中断:
#if DEBUG
if (Debugger.IsAttached)
Debugger.Break();
#endif
Run Code Online (Sandbox Code Playgroud)
using ComplicatedDictionary = Dictionary<int, Dictionary<string, object>>;
ComplicatedDictionary myDictionary = new ComplicatedDictionary();
Run Code Online (Sandbox Code Playgroud)
Mic*_*ows 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.
Run Code Online (Sandbox Code Playgroud)
请注意,上面的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);
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,闭包允许您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);
Run Code Online (Sandbox Code Playgroud)
Hug*_*are 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)) {
...
}
Run Code Online (Sandbox Code Playgroud)
这只是一个例子 - 方法可以使用更多的工作......
Luk*_*ust 36
能够使枚举类型具有除int之外的值(默认值)
public enum MyEnum : long
{
Val1 = 1,
Val2 = 2
}
Run Code Online (Sandbox Code Playgroud)
此外,您可以为该枚举分配任何数值:
MyEnum e = (MyEnum)123;
Run Code Online (Sandbox Code Playgroud)
Jud*_*ngo 36
我今天刚刚发现了这个 - 我和C#一起工作了5年!
它是命名空间别名限定符:
extern alias YourAliasHere;
Run Code Online (Sandbox Code Playgroud)
您可以使用它来加载相同类型的多个版本.这在维护或升级方案中非常有用,在这种情况下,您的类型的更新版本在某些旧代码中不起作用,但您需要将其升级到新版本.Slap在命名空间别名限定符上,编译器将允许您在代码中使用这两种类型.
Kei*_*one 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
Run Code Online (Sandbox Code Playgroud)
该公司的数据访问策略经常受到性能挑战.作为一名架构师,我无法监视每个服务开发人员,以确保他/她编写了一个高性能的数据访问层.但是我在GetDAL工厂模式中可以做的是为请求的DAL 创建透明代理(一旦公共服务模型代码定位DLL并加载它),并使用高性能时序API来分析对所有方法的调用. DAL.然后对落后者进行排名只是通过降低总时间来排序DAL呼叫时间.这种过度开发分析(例如在IDE中)的优点是它也可以在生产环境中完成,以确保SLA.
下面是我为"实体分析器"编写的测试代码示例,它是为单行创建任何类型的分析代理的常用代码:
[Test, Category("ProfileEntity")]
public void MyTest()
{
// this is the object that we want profiled.
// we would normally pass this around and call
// methods on this instance.
DALToBeProfiled dal = new DALToBeProfiled();
// To profile, instead we obtain our proxy
// and pass it around instead.
DALToBeProfiled dalProxy = (DALToBeProfiled)EntityProfiler.Instance(dal);
// or...
DALToBeProfiled dalProxy2 = EntityProfiler<DALToBeProfiled>.Instance(dal);
// Now use proxy wherever we would have used the original...
// All methods' timings are automatically recorded
// with a high-resolution timer
DoStuffToThisObject(dalProxy);
// Output profiling results
ProfileManager.Instance.ToConsole();
}
Run Code Online (Sandbox Code Playgroud)
同样,这允许您拦截客户端在目标对象上调用的所有方法和属性!在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;
}
Run Code Online (Sandbox Code Playgroud)
.NET能做什么并不令人着迷?唯一的限制是目标类型必须从MarshalByRefObject派生.我希望这对某人有帮助.
Joh*_*n K 35
{在成员内的任何地方},{仅使用大括号},{没有控制语句}.
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
}
Run Code Online (Sandbox Code Playgroud)
在大型,混乱或过时的成员(不是它们应该存在)中,它可以帮助我防止使用错误的变量名称.范围更精细的东西.
例如,此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();
Run Code Online (Sandbox Code Playgroud)
(另一个用于保持临时工作不在主范围内的用法)
由Patrik提供:有时用于模仿C#中的VB"with-statement".
var somePerson = this.GetPerson(); // whatever
{
var p = somePerson;
p.FirstName = "John";
p.LastName = "Doe";
//...
p.City = "Gotham";
}
Run Code Online (Sandbox Code Playgroud)
对于挑剔的程序员.
Ris*_*smo 34
没有隐藏,但我认为很多开发人员都没有在可空类型上使用HasValue和Value属性.
int? x = null;
int y;
if (x.HasValue)
y = x.Value;
Run Code Online (Sandbox Code Playgroud)
Sur*_*der 33
我最喜欢的是
global::
Run Code Online (Sandbox Code Playgroud)
用我们的一些第三方代码提供商逃避名称空间地狱的关键字......
例:
global::System.Collections.Generic.List<global::System.String> myList =
new global::System.Collections.Generic.List<global::System.String>();
Run Code Online (Sandbox Code Playgroud)
Zyp*_*rax 32
我已经阅读了所有七页,我错过了这些:
的string.join
我已经看到很多for循环将项目列表转换为带分隔符的字符串.确保不以分隔符开头并且不以分隔符结束总是很痛苦.内置方法使这更容易:
String.Join(",", new String[] { "a", "b", "c"});
Run Code Online (Sandbox Code Playgroud)
TODO在评论中
不是C#功能,更像是Visual Studio功能.当您使用TODO开始发表评论时,它会添加到您的Visual Studio任务列表中(查看 - >任务列表.评论)
// TODO: Implement this!
throw new NotImplementedException();
Run Code Online (Sandbox Code Playgroud)
扩展方法符合泛型
您可以将扩展方法与Generics结合使用,当您考虑本主题前面的技巧时,可以向特定接口添加扩展
public static void Process<T>(this T item) where T:ITest,ITest2 {}
Run Code Online (Sandbox Code Playgroud)
Enumerable.Range
只想要一个整数列表?
Enumerable.Range(0, 15)
Run Code Online (Sandbox Code Playgroud)
我会试着想一些......
cod*_*nix 31
您可以在一个using语句中"使用"多个对象.
using (Font f1= new Font("Arial", 10.0f), f2 = new Font("Arial", 10.0f))
{
// Use f1 and f2.
}
Run Code Online (Sandbox Code Playgroud)
请注意,已经有一个答案表明您可以这样做:
using (Font f1= new Font("Arial", 10.0f))
using (Font f2 = new Font("Arial", 10.0f))
{ }
Run Code Online (Sandbox Code Playgroud)
这与我的不同.
Kim*_*jan 31
宽度 string.Format()
Console.WriteLine("Product: {0,-7} Price: {1,5}", product1, price1);
Console.WriteLine("Product: {0,-7} Price: {1,5}", product2, price2);
Run Code Online (Sandbox Code Playgroud)
产生

Bui*_*ted 31
类型定义
有人发布他们错过了typedef,但你可以这样做
using ListOfDictionary = System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, string>>;
Run Code Online (Sandbox Code Playgroud)
并声明为
ListOfDictionary list = new ListOfDictionary();
Run Code Online (Sandbox Code Playgroud)
nia*_*ith 30
我喜欢关键字continue.
如果你在循环中遇到一个条件并且不想做任何事情而只是推进循环只需坚持"继续;".
例如:
foreach(object o in ACollection)
{
if(NotInterested)
continue;
}
Run Code Online (Sandbox Code Playgroud)
The*_*urf 28
我个人最喜欢的两个,我看到很少使用:
xan*_*ont 28
@lomaxx我前几天也学到了(同时我学到了你的提示)是你现在可以在同一个属性上拥有不同的访问级别:
public string Name { get; private set;}
Run Code Online (Sandbox Code Playgroud)
这样只有类本身才能设置Name属性.
public MyClass(string name) { Name = name; }
Run Code Online (Sandbox Code Playgroud)
jfs*_*jfs 28
使用语句嵌套
通常我们这样做:
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter()) {
using (IndentedTextWriter itw = new IndentedTextWriter(sw)) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
但我们可以这样做:
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter())
using (IndentedTextWriter itw = new IndentedTextWriter(sw)) {
...
}
Run Code Online (Sandbox Code Playgroud)
Igo*_*orM 28
完全访问调用堆栈:
public static void Main()
{
StackTrace stackTrace = new StackTrace(); // get call stack
StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
// write call stack method names
foreach (StackFrame stackFrame in stackFrames)
{
Console.WriteLine(stackFrame.GetMethod().Name); // write method name
}
}
Run Code Online (Sandbox Code Playgroud)
所以,如果你拿第一个 - 你知道你在做什么功能.如果你正在创建一个辅助跟踪功能 - 在最后一个之前拿一个 - 你就会知道你的来电者.
cll*_*pse 28
类似JavaScript的匿名内联函数
返回一个字符串:
var s = new Func<String>(() =>
{
return "Hello World!";
})();
Run Code Online (Sandbox Code Playgroud)
返回一个更复杂的对象:
var d = new Func<Dictionary<Int32, String>>(() =>
{
return new Dictionary<Int32, String>
{
{ 0, "Foo" },
{ 1, "Bar" },
{ 2, "..." }
};
})();
Run Code Online (Sandbox Code Playgroud)
一个真实的用例:
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 = "" }
}
);
Run Code Online (Sandbox Code Playgroud)
注意:您不能在内联函数的范围内重用变量名.
替代语法
// 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 "";
};
Run Code Online (Sandbox Code Playgroud)
缩短字符串并添加水平省略号...
Func<String, String> Shorten = s => s.Length > 100 ? s.Substring(0, 100) + "…" : s;
Run Code Online (Sandbox Code Playgroud)
Mar*_*ade 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);
}
Run Code Online (Sandbox Code Playgroud)
Bry*_*tts 27
按行字段初始化在一行中:
public StringBuilder Builder
{
get { return _builder ?? (_builder = new StringBuilder()); }
}
Run Code Online (Sandbox Code Playgroud)
我不确定我对C#支持赋值表达式的看法,但是,嘿,它在那里:-)
Rom*_*iko 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);
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
IList`1
List`1
Run Code Online (Sandbox Code Playgroud)
它的名字(借用"获取变量名"):
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;
}
Run Code Online (Sandbox Code Playgroud)
结果: Name is 'args'
GvS*_*GvS 26
该Environment.UserInteractive财产.
UserInteractive属性为Windows进程或IIS等服务报告错误,该服务在没有用户界面的情况下运行.如果此属性为false,则不显示模式对话框或消息框,因为没有用户可以与之交互的图形用户界面.
Inc*_*ito 26
AppDomain.UnhandledException事件也是隐藏的候选者.
此事件提供未捕获异常的通知.它允许应用程序在系统默认处理程序向用户报告异常并终止应用程序之前记录有关异常的信息.如果有足够的有关应用程序状态的信息,则可以采取其他措施 - 例如保存程序数据以便以后恢复.建议小心,因为在未处理异常时程序数据可能会损坏.
我们可以看到,即使在这个网站上,也有很多人想知道为什么他们的应用程序没有启动,为什么崩溃等等.AppDomain.UnhandledException事件对于这种情况非常有用,因为它提供了至少记录应用原因的可能性失败.
Fre*_*nge 25
C#?? null合并运算符 -
没有真正隐藏,但很少使用.可能是因为很多开发人员在看到有条件的时候跑了一英里?操作员,所以当他们看到这个时他们跑两个.用过的:
string mystring = foo ?? "foo was null"
Run Code Online (Sandbox Code Playgroud)
而不是
string mystring;
if (foo==null)
mystring = "foo was null";
else
mystring = foo;
Run Code Online (Sandbox Code Playgroud)
Rob*_*gin 25
该#如果DEBUG预处理器指令.它对测试和调试很有用(虽然我通常更喜欢单元测试路线).
string customerName = null;
#if DEBUG
customerName = "Bob"
#endif
Run Code Online (Sandbox Code Playgroud)
如果Visual Studio设置为在"调试"模式下编译,它将只执行代码块.否则编译器将忽略代码块(并在Visual Studio中显示为灰色).
Moh*_*eer 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();
Run Code Online (Sandbox Code Playgroud)
代替
return string.Join(separator, list.ToArray());
Run Code Online (Sandbox Code Playgroud)
Pop*_*lin 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));
}}
Run Code Online (Sandbox Code Playgroud)
Rom*_*iko 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);
}
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
参见Richter,J.CLR via C#,2nd edition,chapter 14:Interfaces,section about Generics and Interface Constraints.
另见我对另一个问题的回答.
mgs*_*oan 22
已经提到了所有凉爽的附近.不确定这个是否众所周知
C#property/field构造函数初始化:
var foo = new Rectangle()
{
Fill = new SolidColorBrush(c),
Width = 20,
Height = 20
};
Run Code Online (Sandbox Code Playgroud)
这将创建矩形,并设置列出的属性.
我注意到了一些有趣的东西 - 你可以在属性列表的末尾加一个逗号,而不会出现语法错误.所以这也是有效的:
var foo = new Rectangle()
{
Fill = new SolidColorBrush(c),
Width = 20,
Height = 20,
};
Run Code Online (Sandbox Code Playgroud)
Wil*_*ean 21
基于这个主题应该被称为" 直到最近你还不知道关于C#的事情,尽管认为你已经知道了所有事情 ",我的个人特征是异步代表.
直到我读到Jeff Richter的C#/ CLR书(优秀的书,每个人都在读.NET)我不知道你可以用/ 调用任何代表.我倾向于做很多调用(我猜这很像是委托在内部做的事情),但是有时添加标准化的连接/会合模式可能非常有用.BeginInvokeEndInvokeThreadPool.QueueUserWorkItemBeginInvoke
ope*_*lar 21
有几个人提到使用积木,但我认为它们比人们意识到的要有用得多.把它们想象成穷人的AOP工具.我有许多简单的对象,它们在构造函数中捕获状态,然后在Dispose()方法中恢复它.这允许我将一个功能包装在一个使用块中,并确保在最后恢复状态.例如:
using(new CursorState(this, BusyCursor));
{
// Do stuff
}
Run Code Online (Sandbox Code Playgroud)
CursorState捕获表单使用的当前游标,然后设置表单以使用提供的游标.最后它恢复原始光标.我做了很多这样的事情,例如在刷新之前捕获网格上的选择和当前行等等.
Bil*_*rry 21
关于事件处理程序的另一个注意事项:您可以像这样简单地创建一个raise extension方法:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以用它来举起事件:
public class MyImportantThing {
public event EventHandler<MyImportantEventEventArgs> SomethingHappens;
...
public void Bleh() {
SomethingHappens.Raise(this, new MyImportantEventEventArgs { X=true });
}
}
Run Code Online (Sandbox Code Playgroud)
该方法具有强制执行编码标准(使用EventHandler<>)的附加优点.
一遍又一遍地写出相同的功能是没有意义的.也许C#的下一个版本最终会有一个InlineAttribute可以放在扩展方法上,并且会使编译器内联方法定义(这将使这种方式接近标准,并且最快).
编辑:根据注释删除扩展方法中的临时变量
Joe*_*orn 20
我参加这个派对已经很晚了,所以我的第一选择已经开始了.但我没有看到有人提到这个宝石:
它有一些东西,比如使用Parallel.ForEach替换Parallel.For或foreach
并行示例:
在您看来,一秒钟内可以创建多少个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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 20
我喜欢的一个很棒的类是System.Xml.XmlConvert可以用来从xml标签读取值.特别是,如果我从xml属性或元素中读取布尔值,我会使用
bool myFlag = System.Xml.XmlConvert.ToBoolean(myAttribute.Value);
Run Code Online (Sandbox Code Playgroud)
注意:由于xml中的boolean类型除了"true"和"false"之外还接受1和0作为有效值,因此在这种情况下使用字符串比较容易出错.
Dav*_*nde 20
每个人都看过一个.基本上,当你看到这个:
[assembly: ComVisible(false)]
Run Code Online (Sandbox Code Playgroud)
该属性的"assembly:"部分是目标.在这种情况下,属性将应用于程序集,但还有其他属性:
[return: SomeAttr]
int Method3() { return 0; }
Run Code Online (Sandbox Code Playgroud)
在此示例中,该属性应用于返回值.
rik*_*koe 20
对于发布这么晚的道歉,我是Stack Overflow的新手,所以错过了之前的机会.
我发现这EventHandler<T>是一个未充分利用的框架的一个很棒的特性.
我遇到的大多数C#开发人员在定义自定义事件时仍定义自定义事件处理程序委托,这根本就不再需要了.
代替:
public delegate void MyCustomEventHandler(object sender, MyCustomEventArgs e);
public class MyCustomEventClass
{
public event MyCustomEventHandler MyCustomEvent;
}
Run Code Online (Sandbox Code Playgroud)
你可以走了:
public class MyCustomEventClass
{
public event EventHandler<MyCustomEventArgs> MyCustomEvent;
}
Run Code Online (Sandbox Code Playgroud)
这更简洁,而且你不会陷入是否将委托放在包含事件的类的.cs文件或EventArgs派生类的困境中.
ntz*_*lis 20
IObservable怎么样?
几乎每个人都知道IEnumerable,但他们的数学对偶似乎是未知的IObservable.也许是因为它在.NET 4中的新功能.
它所做的不是拉动信息(如可枚举的信息)而是将信息推送到可观察者的订户.
与Rx扩展一起,它将改变我们处理事件的方式.只是想说明它是多么强大的检查很短的例子在这里.
Tho*_*que 20
好吧,这看起来很明显,但我想提一下Object.Equals方法(静态方法,有两个参数).
我很确定很多人甚至都不知道它,或者忘记了它,但在某些情况下它确实有用.例如,当您想比较两个对象是否相等时,不知道它们是否为空.你写了多少次这样的东西:
if ((x == y) || ((x != null && y != null) && x.Equals(y)))
{
...
}
Run Code Online (Sandbox Code Playgroud)
当你可以写:
if (Object.Equals(x, y))
{
...
}
Run Code Online (Sandbox Code Playgroud)
(Object.Equals实际上与第一个代码示例完全相同)
Dan*_*ann 20
string.Empty
Run Code Online (Sandbox Code Playgroud)
我知道这不是幻想(荒唐奇怪),但我一直用它来代替"".
它会被隐藏起来,直到有人告诉你它在那里.
Mar*_*ade 19
C#3.0的LINQ查询理解是一个完整的monadic理解 和 Haskell(实际上它们是由Haskell的一个设计者设计的).它们适用于"LINQ模式"之后的任何泛型类型,并允许您以纯monadic函数样式编写,这意味着所有变量都是不可变的(就好像您使用的唯一变量是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 */
});
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*unn 19
不是真的隐藏,但有用.当你有一个enum带flags,你可以使用左移位,使事情更加清楚.例如
[Flags]
public enum ErrorTypes {
None = 0,
MissingPassword = 1 << 0,
MissingUsername = 1 << 1,
PasswordIncorrect = 1 << 2
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*old 18
我最喜欢的属性:InternalsVisibleTo
在装配级别,您可以声明另一个装配可以看到您的内部.出于测试目的,这绝对是美妙的.
将它粘贴在AssemblyInfo.cs或同等版本中,您的测试程序集就可以完全访问需要测试的所有内部资源.
[assembly: InternalsVisibleTo("MyLibrary.Test, PublicKey=0024...5c042cb")]
Run Code Online (Sandbox Code Playgroud)
如您所见,测试程序集必须具有强名称才能获得被测程序集的信任.
提供.Net Framework 2.0 +,Compact Framework 2.0+和XNA Framework 1.0+.
Nat*_*Lee 17
我喜欢使用@字符进行SQL查询.它使sql保持良好和格式化,而不必用字符串分隔符包围每一行.
string sql = @"SELECT firstname, lastname, email
FROM users
WHERE username = @username AND password = @password";
Run Code Online (Sandbox Code Playgroud)
Kei*_*ler 17
您可以使用{ }括号限制变量的寿命和范围.
{
string test2 = "3";
Console.Write(test2);
}
Console.Write(test2); //compile error
Run Code Online (Sandbox Code Playgroud)
test2 只生活在括号内.
小智 17
需要返回一个空的IEnumerable吗?
public IEnumerable<T> GetEnumerator(){
yield break;
}
Run Code Online (Sandbox Code Playgroud)
Rin*_*lin 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'
Run Code Online (Sandbox Code Playgroud)
有关更多详细信息,请参阅如何在C#中找出变量或参数名称?
FFi*_*ire 16
您可以在Enum中存储颜色.
public enum MyEnumColors : uint
{
Normal = 0xFF9F9F9F,
Active = 0xFF8EA98A,
Error = 0xFFFF0000
}
Run Code Online (Sandbox Code Playgroud)
Lar*_*lum 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
private void SomeEventHappened(object sender, EventArgs e)
{
Filters.SomeValue = SomeControl.SelectedValue;
}
private void TimeToFetchSomeData()
{
GridView.DataSource = Repository.GetList(Filters);
}
Run Code Online (Sandbox Code Playgroud)
这个关于"where ParameterType:BaseParameterType,new"的小技巧是让它真正起作用的原因.
在我的基类中使用此属性,我可以自动处理分页,设置过滤器值以过滤网格视图,使排序变得非常简单等.
我只是说仿制药可以成为一个非常强大的野兽.
Mar*_*rke 15
如何在枚举上使用FlagsAttribute?它允许您执行按位操作...让我永远地了解如何在.NET中进行按位操作.
Tor*_*gen 15
您可以在C#名称中使用任何Unicode字符,例如:
public class MyClass
{
public string Hårføner()
{
return "Yes, it works!";
}
}
Run Code Online (Sandbox Code Playgroud)
您甚至可以使用Unicode转义.这个相当于上面的:
public class MyClass
{
public string H\u00e5rføner()
{
return "Yes, it (still) works!";
}
}
Run Code Online (Sandbox Code Playgroud)
小智 15
您可以使用较少的键入来添加和删除委托.
通常的方式:
handler += new EventHandler(func);
Run Code Online (Sandbox Code Playgroud)
减少打字方式:
handler += func;
Run Code Online (Sandbox Code Playgroud)
Edi*_*ang 15
使用带有FlagAttribute和enum的"〜"运算符
有时我们会使用带有枚举的Flag属性对枚举执行按位操作.
[Flags]
public enum Colors
{
None = 0,
Red = 1,
Blue = 2,
White = 4,
Black = 8,
Green = 16,
All = 31 //It seems pretty bad...
}
Run Code Online (Sandbox Code Playgroud)
请注意,枚举中选项"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.
}
Run Code Online (Sandbox Code Playgroud)
Inc*_*ito 15
也很有用,但不常用:约束执行区域.
BCL团队博客引用:
存在约束执行区域(CER)以帮助开发人员编写代码以保持一致性.CLR不保证开发人员的代码是正确的,但CLR确实将所有运行时引发的故障点(即异步异常)提升到代码运行之前或完成之后.结合对开发人员可以放入CER的限制,这些是对代码是否执行提供强有力保证的有用方法.CER正在热切地准备,这意味着当我们看到一个时,我们将急切地JIT在其静态可发现的调用图中找到的任何代码.如果CLR的主机关心堆栈溢出,我们也将探测一些堆栈空间(尽管可能没有足够的堆栈空间用于任何方法*).
在以原子方式对数据结构的多个字段进行编辑时,它非常有用.因此,在对象上进行事务是有帮助的.
此外CriticalFinalizerObject似乎被隐藏(至少谁不写不安全的代码).CriticalFinalizerObject保证垃圾收集将执行终结器.在分配时,终结器及其调用图是预先准备的.
And*_*rns 14
允许您告诉编译器在特定条件下(#define)省略对使用该属性标记的方法的调用.
省略方法调用的事实也意味着不评估其参数.这非常方便,它允许您在Debug.Assert()中调用昂贵的验证函数,而不用担心它们会减慢您的发布版本.
Mih*_*zar 14
我在Stack Overflow上只学到的一个功能是能够在返回参数上设置属性.
[AttributeUsage( AttributeTargets.ReturnValue )]
public class CuriosityAttribute:Attribute
{
}
public class Bar
{
[return: Curiosity]
public Bar ReturnANewBar()
{
return new Bar();
}
}
Run Code Online (Sandbox Code Playgroud)
这对我来说真的是一个隐藏的功能:-)
tsi*_*ilb 14
标记我的终端区域......
#region stuff1
#region stuff1a
//...
#endregion stuff1a
#endregion stuff1
Run Code Online (Sandbox Code Playgroud)
cod*_*nix 14
定义自定义属性时,可以将它们与[MyAttAttribute]或[MyAtt]一起使用.当两个着作都存在类时,就会发生编译错误.
@ special字符可用于区分它们:
[AttributeUsage(AttributeTargets.All)]
public class X: Attribute
{}
[AttributeUsage(AttributeTargets.All)]
public class XAttribute: Attribute
{}
[X] // Error: ambiguity
class Class1 {}
[XAttribute] // Refers to XAttribute
class Class2 {}
[@X] // Refers to X
class Class3 {}
[@XAttribute] // Refers to XAttribute
class Class4 {}
Run Code Online (Sandbox Code Playgroud)
Jeh*_*hof 14
当一个类实现INotifyPropertyChanged并且您想要通知绑定系统(WPF,Silverlight等)时,对象(ViewModel)的多个绑定属性已更改,您可以使用null或String.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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Oza*_*zan 14
您可以在一对方括号中放置几个属性:
[OperationContract, ServiceKnownType(typeof(Prism)), ServiceKnownType(typeof(Cuboid))]
Shape GetShape();
Run Code Online (Sandbox Code Playgroud)
t3r*_*rse 13
Lambda表达式
Func<int, int, int> add = (a, b) => (a + b);
Run Code Online (Sandbox Code Playgroud)
模糊的字符串格式
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] );
}
Run Code Online (Sandbox Code Playgroud)
小智 13
怎么样使用这个:
#if DEBUG
Console.Write("Debugging");
#else
Console.Write("Final");
#endif
Run Code Online (Sandbox Code Playgroud)
当您使用DEBUG定义编译解决方案时,它将输出"Debugging".
如果您的编译设置为Release,它将写入"Final".
And*_*ers 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
Run Code Online (Sandbox Code Playgroud)
Bri*_*iec 13
我正在成为扩展方法的忠实粉丝,因为它们可以为现有代码或无法编辑的代码添加许多想要的功能.我最喜欢的一个是我现在所做的一切是string.IsNullOrEmpty()
public static class Strings
{
public static bool IsNullOrEmpty(this string value)
{
return string.IsNullOrEmpty(value);
}
}
Run Code Online (Sandbox Code Playgroud)
这使您可以像这样缩短代码
var input = Console.ReadLine();
if (input.IsNullOrEmpty())
{
Console.WriteLine("try again");
}
Run Code Online (Sandbox Code Playgroud)
thr*_*thr 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;
}
}
Run Code Online (Sandbox Code Playgroud)
每个人都知道如何创建它的实例,例如:
Tuple<int, string> tup = new Tuple<int, string>(1, "Hello, World!");
Run Code Online (Sandbox Code Playgroud)
不完全是火箭科学,现在我们当然可以将变量的类型声明更改为var,如下所示:
var tup = new Tuple<int, string>(1, "Hello, World!");
Run Code Online (Sandbox Code Playgroud)
仍然众所周知,这里有一个带有类型参数的静态方法,每个人都应该熟悉:
public static void Create<T1, T2>()
{
// stuff
}
Run Code Online (Sandbox Code Playgroud)
再一次常识,这就是这样做的:
Create<float, double>();
Run Code Online (Sandbox Code Playgroud)
大多数人不知道的是,如果泛型方法的参数包含它所需的所有类型,则可以推断它们,例如:
public static void Create<T1, T2>(T1 a, T2 b)
{
// stuff
}
Run Code Online (Sandbox Code Playgroud)
这两个电话是相同的:
Create<float, string>(1.0f, "test");
Create(1.0f, "test");
Run Code Online (Sandbox Code Playgroud)
因为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);
}
}
Run Code Online (Sandbox Code Playgroud)
达到这个效果:
var tup = Tuple.Create(1, "Hello, World!");
Run Code Online (Sandbox Code Playgroud)
这意味着:变量"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");
Run Code Online (Sandbox Code Playgroud)
它为您提供完全类型推断的工厂方法!
cll*_*pse 13
使用LINQ轻松实现眼睛/浓缩ORM映射
考虑一下这个表:
[MessageId] INT,
[MessageText] NVARCHAR(MAX)
[MessageDate] DATETIME
Run Code Online (Sandbox Code Playgroud)
......而这个结构:
struct Message
{
Int32 Id;
String Text;
DateTime Date;
}
Run Code Online (Sandbox Code Playgroud)
而不是做以下事情:
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);
}
Run Code Online (Sandbox Code Playgroud)
你可以使用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();
Run Code Online (Sandbox Code Playgroud)
这种方法可以嵌套,就像循环一样.
Ale*_*man 12
通过下降switch- caseS可通过不具有代码在一个来实现case(见case 0),或者使用特殊的goto case(见case 1)或goto default(见case 2)形式:
switch (/*...*/) {
case 0: // shares the exact same code as case 1
case 1:
// do something
goto case 2;
case 2:
// do something else
goto default;
default:
// do something entirely different
break;
}
Run Code Online (Sandbox Code Playgroud)
Coh*_*hen 12
我错过了很长一段时间的东西:你可以比较字符串
"string".equals("String", StringComparison.InvariantCultureIgnoreCase)
Run Code Online (Sandbox Code Playgroud)
而不是做:
"string".ToLower() == "String".ToLower();
Run Code Online (Sandbox Code Playgroud)
tui*_*oel 12
如果方法参数实现了两个接口,则可以使用泛型来检查(编译时):
interface IPropA
{
string PropA { get; set; }
}
interface IPropB
{
string PropB { get; set; }
}
class TestClass
{
void DoSomething<T>(T t) where T : IPropA, IPropB
{
MessageBox.Show(t.PropA);
MessageBox.Show(t.PropB);
}
}
Run Code Online (Sandbox Code Playgroud)
与从基类和接口继承的参数相同.
Pau*_*ane 12
我能想到的一对夫妇:
[field: NonSerialized()]
public EventHandler event SomeEvent;
Run Code Online (Sandbox Code Playgroud)
这可以防止事件被序列化.'field:'表示该属性应该应用于事件的支持字段.
另一个鲜为人知的功能是覆盖add/remove事件处理程序:
public event EventHandler SomeEvent
{
add
{
// ...
}
remove
{
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
Dun*_*art 11
我喜欢这样的事实:我可以在普通的旧版.NET 2.0上使用LINQ来对象(即不需要在任何地方安装.NET 3.5).您所需要的只是所有查询运算符Extension方法的实现 - 请参阅LINQBridge
Ben*_*jol 11
我还无法发表评论,但请注意,默认情况下,Visual Studio 2008会自动切换属性,因此在这种情况下不再需要DebuggerStepThrough属性.
另外,我没有注意到有人展示如何声明一个无参数的lambda(对于实现Action <>很有用)
() => DoSomething(x);
你还应该阅读关闭 - 我不够聪明,无法正确解释它们.但基本上它意味着编译器会做一些聪明的事情,以便即使在创建lambda之后它超出范围,代码行中的x仍然可以工作.
我最近也发现你可以假装忽略一个lambda参数:
(e, _) => DoSomething(e)
它并不是真的忽略它,只是_是一个有效的标识符.所以你不能忽略这两个参数,但我认为这是一种巧妙的方式来表明我们不关心那个参数(通常是EventArgs .Empty).
Flo*_*ory 11
在声明的类和一个或多个任意类之间存在用于执行implicit和explicit用户定义的类型转换的运算符.的implicit操作者有效地允许重载assignement操作者,这是在语言可能的,诸如C++但不C#的模拟.
它似乎不是经常出现的功能,但实际上它在LINQ to XML(System.Xml.Linq)库中使用,您可以在其中隐式地将字符串转换为XName对象.例:
XName tagName = "x:Name";
Run Code Online (Sandbox Code Playgroud)
我在本文中发现了有关如何在C#中模拟多重继承的这一特性.
Phi*_*gan 11
委托语法已经在C#的连续版本中发展,但我仍然发现它们很难记住.幸运的是Action<>,Func<>代表们很容易记住.
例如:
Action<int> 是一个委托方法,它接受一个int参数并返回void.Func<int> 是一个委托方法,不带参数并返回一个int.Func<int, bool> 是一个委托方法,它接受一个int参数并返回一个bool.这些功能是在.NET框架的3.5版本中引入的.
Wim*_*nen 11
可以调用扩展方法null; 这不会导致NullReferenceException抛出.
示例应用程序:您可以为ToString()被调用定义一个替代方法ToStringOrEmpty(),它将在调用时返回空字符串null.
Bin*_*ony 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
}
}
Run Code Online (Sandbox Code Playgroud)
当然,你只需说出就可以调用基类的方法 base.MethodName()
Mor*_*man 10
TrueForAll方法List<T>:
List<int> s = new List<int> { 6, 1, 2 };
bool a = s.TrueForAll(p => p > 0);
Run Code Online (Sandbox Code Playgroud)
nsa*_*llo 10
很少有人知道的一件事是一些C#引入的预处理器指令.您可以使用#error This is an error.生成编译器错误和#warning This is a warning.
当我使用自上而下的方法开发作为"待办事项"列表时,我通常使用这些.我会#error Implement this function,或者#warning Eventually implement this corner case作为提醒.
Tit*_*mir 10
不确定这个是否已被提及,但ThreadStatic属性是一个非常有用的属性.这使静态字段仅为当前线程静态.
[ThreadStatic]
private static int _ThreadStaticInteger;
Run Code Online (Sandbox Code Playgroud)
你不应该包含一个初始值设定项,因为它只对整个应用程序执行一次,你最好使字段可以为空,并在使用之前检查值是否为null.
ASP.NET应用程序线程的另一个用途是重用,因此如果修改该值,它最终可能会被用于另一个页面请求.
我仍然发现这有用几次.例如,在创建自定义事务类时:
using (DbTransaction tran = new DbTransaction())
{
DoQuery("...");
DoQuery("...");
}
Run Code Online (Sandbox Code Playgroud)
DbTransaction构造函数将ThreadStatic字段设置为self,并在dispose方法中将其重置为null.DoQuery检查静态字段,如果!= null使用当前事务,否则默认为其他事务.我们避免必须将事务传递给每个方法,而且它可以很容易地包装其他方法,这些方法原本不是用于事务中的事务...
只需一次使用:)
Mar*_*ann 10
该Or赋值运算符是相当不错的.你可以这样写:
x |= y
Run Code Online (Sandbox Code Playgroud)
而不是这个:
x = x | y
Run Code Online (Sandbox Code Playgroud)
如果你有一个变量或属性(这通常是实际x启动了作为例子)false,但你想改变它的一些其他的布尔变量/属性的值,只有当其他值true.
jpi*_*son 10
嵌套类可以访问外部类的私有成员.
public class Outer
{
private int Value { get; set; }
public class Inner
{
protected void ModifyOuterMember(Outer outer, int value)
{
outer.Value = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,与上述功能一起,您也可以从嵌套类继承,就像它们是顶级类一样,如下所示.
public class Cheater : Outer.Inner
{
protected void MakeValue5(Outer outer)
{
ModifyOuterMember(outer, 5);
}
}
Run Code Online (Sandbox Code Playgroud)
这些功能允许一些有趣的可能性,只要通过隐藏的类提供对特定成员的访问.
Dar*_*usz 10
您可以使用以下方法更改舍入方案:
var value = -0.5;
var value2 = 0.5;
var value3 = 1.4;
Console.WriteLine( Math.Round(value, MidpointRounding.AwayFromZero) ); //out: -1
Console.WriteLine(Math.Round(value2, MidpointRounding.AwayFromZero)); //out: 1
Console.WriteLine(Math.Round(value3, MidpointRounding.ToEven)); //out: 1
Run Code Online (Sandbox Code Playgroud)
System.Diagnostics.Debug.Assert (false);
Run Code Online (Sandbox Code Playgroud)
将触发弹出窗口并允许您在执行期间将调试器附加到正在运行的.NET进程.由于某些原因您无法直接调试ASP.NET应用程序时非常有用.
字符串实习.这是我尚未见过的讨论.它有点模糊,但在某些条件下它可能是有用的.
CLR保留一个对文字字符串的引用表(以及以编程方式实现的字符串).如果在代码中的多个位置使用相同的字符串,它将在表中存储一次.这可以减轻分配字符串所需的内存量.
您可以使用String.IsInterned(string)测试字符串是否被中断,并且您可以使用String.Intern(string)实习字符串.
注意: CLR可以在应用程序甚至AppDomain结束后保留对实习字符串的引用.有关详细信息,请参阅MSDN文档.
IEnumerable的SelectMany,它将列表列表展平为单个列表.假设我有一个清单Orders,每个Order清单都有一个清单LineItems.
我想知道LineItems售出的总数......
int totalItems = Orders.Select(o => o.LineItems).SelectMany(i => i).Sum();
Run Code Online (Sandbox Code Playgroud)
使用枚举.
将字符串转换为枚举:
enum MyEnum
{
FirstValue,
SecondValue,
ThirdValue
}
string enumValueString = "FirstValue";
MyEnum val = (MyEnum)Enum.Parse(typeof(MyEnum), enumValueString, true)
Run Code Online (Sandbox Code Playgroud)
比较enum类型的变量时,不必转换为int:
MyEnum val = MyEnum.SecondValue;
if (val < MyEnum.ThirdValue)
{
// Do something
}
Run Code Online (Sandbox Code Playgroud)
我非常喜欢函数的隐式泛型参数.例如,如果您有:
public void DoStuff<T>(T value);
Run Code Online (Sandbox Code Playgroud)
而不是像这样调用它:
DoStuff<int>(5);
Run Code Online (Sandbox Code Playgroud)
您可以:
DoStuff(5);
Run Code Online (Sandbox Code Playgroud)
它将从参数的类型中找出泛型类型.
要<T>使用LINQ 测试IEnumerable 是否为空,请使用:
IEnumerable
<T>.Any();
<T>.Count()!= 0)...
<T>枚举IEnumerable中的所有项目.<T>.FirstOrDefault()== null)...
<T>.Any()是最简洁的,表现最好.我很确定每个人都熟悉运算符重载,但也许有些不是.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为能够使用<<和>>左右移动字符串或使用 - =删除一组遵循正则表达式模式的字符串是非常酷的
myClass tmpClass = new myClass(" HelloWorld123");
tmpClass -= @"World";
tmpClass <<= 2;
Console.WriteLine(tmpClass);
Run Code Online (Sandbox Code Playgroud)
不是C#特定的东西,但我是一个三元手术迷.
代替
if (boolean Condition)
{
//Do Function
}
else
{
//Do something else
}
Run Code Online (Sandbox Code Playgroud)
你可以使用简洁
booleanCondtion ? true operation : false operation;
Run Code Online (Sandbox Code Playgroud)
例如
代替
int value = param;
if (doubleValue)
{
value *= 2;
}
else
{
value *= 3;
}
Run Code Online (Sandbox Code Playgroud)
你可以输入
int value = param * (tripleValue ? 3 : 2);
Run Code Online (Sandbox Code Playgroud)
它确实有助于编写简洁的代码,但嵌套该死的东西可能是令人讨厌的,它们可以用于邪恶,但我喜欢这些小吸盘
你可以打开字符串!
switch(name)
{
case "Dave":
return true;
case "Bob":
return false;
default:
throw new ApplicationException();
}
Run Code Online (Sandbox Code Playgroud)
非常便利!并且比一堆if-else语句更清晰
而不是做这样的俗气:
Console.WriteLine("{0} item(s) found.", count);
Run Code Online (Sandbox Code Playgroud)
我使用以下内联技巧:
Console.WriteLine("{0} item{1} found.", count, count==1 ? "" : "s");
Run Code Online (Sandbox Code Playgroud)
当有一个项目时,这将显示"项目",或者当有更多(或更少)项目时,这将显示"项目".没有多少努力获得一点专业性.
在C#3.5中初始化Dictionary的表达式:
new Dictionary<string, Int64>() {{"Testing", 123}, {"Test", 125}};
C#允许您将属性setter方法添加到实现只读接口属性的具体类型,即使接口声明本身没有属性设置器.例如:
public interface IReadOnlyFoo
{
object SomeReadOnlyProperty { get; }
}
Run Code Online (Sandbox Code Playgroud)
具体类看起来像这样:
internal class Foo : IReadOnlyFoo
{
public object SomeReadOnlyProperty { get; internal set; }
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果将它转换为IReadOnlyFoo接口,Foo类是不可变的:
// Create a Foo instance
Foo foo = new Foo();
// This statement is legal
foo.SomeReadOnlyProperty = 12345;
// Make Foo read only
IReadOnlyFoo readOnlyFoo = foo;
// This statement won't compile
readOnlyFoo.SomeReadOnlyProperty = 54321;
Run Code Online (Sandbox Code Playgroud)
字典初始化器对于需要对某些数据进行硬编码的快速黑客攻击和单元测试总是很有用.
var dict = new Dictionary<int, string> { { 10, "Hello" }, { 20, "World" } };
Run Code Online (Sandbox Code Playgroud)
使用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();
}
Run Code Online (Sandbox Code Playgroud)
除了duncansmart的回复之外,还可以在Framework 2.0上使用扩展方法.只需ExtensionAttribute在System.Runtime.CompilerServices命名空间下添加一个类,就可以使用扩展方法(当然只能使用C#3.0).
namespace System.Runtime.CompilerServices
{
public class ExtensionAttribute : Attribute
{
}
}
Run Code Online (Sandbox Code Playgroud)
您键入"prop",然后按[TAB]两次,它会为您的属性生成有用的代码,并可以加快您的输入速度.
我知道这可以在VS 2005中使用(我使用它),但我不知道以前的版本.
确定指定的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));
Run Code Online (Sandbox Code Playgroud)
与"=="和".Equals"的区别:
基本上,对象A的Equals()测试与对象B具有相同的内容.
System.Object.ReferenceEquals()方法始终比较引用.尽管类可以为等于运算符(下面)提供自己的行为,但是如果通过对System.Object的引用调用运算符,则不会调用该重定义的运算符.
对于字符串,没有什么区别,因为已经重写了==和Equals来比较字符串的内容.
另请参阅另一个问题的答案("如何在没有无限递归的情况下检查'=='运算符重载中的空值?").
这不是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的构造函数的参数隐藏起来,这太糟糕了.
仍然 - 非常隐藏.:)
C#4.0中的动态关键字
如果希望仅在运行时解析方法调用,则可以使用dynamic关键字.
dynamic invoker=new DynamicInvoker();
dynamic result1=invoker.MyMethod1();
dynamic result2=invoker.MyMethod2();
Run Code Online (Sandbox Code Playgroud)
在这里,我正在实现一个动态调用程序.
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
}
}
Run Code Online (Sandbox Code Playgroud)
使用lambda时模拟功能性"通配符"参数(如Haskell中的"_")的酷技巧:
(_, b, __) => b.DoStuff(); // only interested in b here
Run Code Online (Sandbox Code Playgroud)
这是我最近发现的一个有用的:
Microsoft.VisualBasic.Logging.FileLogTraceListener
Run Code Online (Sandbox Code Playgroud)
这是一个TraceListener实现,它具有许多功能,例如自动日志文件翻转,我以前会使用自定义日志记录框架.好处是它是.NET的核心部分,并与Trace框架集成,因此易于立即使用和使用.
这是"隐藏"的,因为它在Microsoft.VisualBasic程序集中......但您也可以在C#中使用它.
在通用代码中使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
当您想要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();
}
);
}
}
Run Code Online (Sandbox Code Playgroud)
解决了错误:"无法将匿名方法转换为'System.Delegate',因为它不是委托类型".
数组初始化而不指定数组元素类型:
var pets = new[] { "Cat", "Dog", "Bird" };
Run Code Online (Sandbox Code Playgroud)
查看组件时要显示的属性设计视图中的属性:
private double _Zoom = 1;
[Category("View")]
[Description("The Current Zoom Level")]
public double Zoom
{
get { return _Zoom;}
set { _Zoom = value;}
}
Run Code Online (Sandbox Code Playgroud)
使组件库的其他用户更容易.
已提到的属性DebuggerDisplay和DebuggerBrowsable控制元素的可见性和显示的文本值.简单地重写ToString()将导致调试器使用该方法的输出.
如果您想要更复杂的输出,可以使用/创建Debugger Visualizer,这里有几个示例.
Microsoft提供称为SOS的调试器扩展.这是一个非常强大(虽然经常令人困惑)的扩展,这是诊断"泄漏"的一种很好的方法,更准确地说是对不再需要的对象的不必要的引用.
遵循这些说明将允许您逐步完成框架的某些部分的来源.
Visual Studio 2010中存在一些增强功能和新功能:
您可以使用扩展方法创建委托,就好像它们是常规方法一样,从而调整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"
Run Code Online (Sandbox Code Playgroud)
请注意,这不适用于扩展值类型的扩展方法; 看到这个问题.
小智 7
HttpContext.Current.Server.Execute
Run Code Online (Sandbox Code Playgroud)
非常适合将HTML呈现为AJAX回调的字符串.您可以将其与组件一起使用,而不是拼凑HTML字符串片段.我能够将页面臃肿减少几百KB,几乎没有任何混乱.我用它是这样的:
Page pageHolder = new Page();
UserControl viewControl = (UserControl)pageHolder.LoadControl(@"MyComponent.ascx");
pageHolder.Controls.Add(viewControl);
StringWriter output = new StringWriter();
HttpContext.Current.Server.Execute(pageHolder, output, false);
return output.ToString();
Run Code Online (Sandbox Code Playgroud)
[field: NonSerialized]
public event EventHandler Event;
Run Code Online (Sandbox Code Playgroud)
这样,事件侦听器就不会被序列化.
只是[NonSerialized]不起作用,因为NonSerializedAttribute只能应用于字段.
我不认为有人提到追加?在值类型名称之后将使其可为空.
你可以做:
DateTime? date = null;
Run Code Online (Sandbox Code Playgroud)
DateTime是一个结构.
我喜欢
#if DEBUG
//Code run in debugging mode
#else
//Code run in release mode
#endif
Run Code Online (Sandbox Code Playgroud)
我正在通过"Pro ASP.NET MVC框架"(APress)这本书阅读并观察到作者正在使用对我来说很陌生的Dictionary对象.
他在不使用Add()方法的情况下添加了一个新的键/值对.然后他覆盖相同的键/值对,而不必检查该键是否已存在.例如:
Dictionary<string, int> nameAgeDict = new Dictionary<string, int>();
nameAgeDict["Joe"] = 34; // no error. will just auto-add key/value
nameAgeDict["Joe"] = 41; // no error. key/value just get overwritten
nameAgeDict.Add("Joe", 30); // ERROR! key already exists
Run Code Online (Sandbox Code Playgroud)
在许多情况下,我不需要检查我的词典是否已经有一个键,我只想添加相应的键/值对(如果需要,覆盖现有的键/值对.)在此发现之前,我总是要在添加之前检查密钥是否已经存在.
不确定这个是否被提及(11页!!)
但是,OptionalField当您对将要序列化的类/对象进行版本控制时,类的属性是惊人的.
http://msdn.microsoft.com/en-us/library/ms229752(VS.80).aspx
@Brad Barker
我认为如果你必须使用可空类型,最好使用Nullable <.T>而不是问号符号.令人惊讶的是,魔法正在发生.不知道为什么有人会想要使用Nullable <.bool>.:-)
Krzysztof Cwalina(Framwork Design Guidlines的作者之一)在这里有一篇好文章:http: //blogs.msdn.com/kcwalina/archive/2008/07/16/Nullable.aspx
Mike Hadlow在Nullability Voodoo上发表了一篇不错的帖子
在阅读有关.NET框架开发的书中.一个很好的建议是不要使用bool打开或关闭东西,而是使用ENums.
使用ENums,您可以为自己提供一些可扩展性,而无需重写任何代码来为函数添加新功能.
想到@dp AnonCast并决定尝试一下.以下是我提出的可能对某些人有用的内容:
// using the concepts of dp's AnonCast
static Func<T> TypeCurry<T>(Func<object> f, T type)
{
return () => (T)f();
}
Run Code Online (Sandbox Code Playgroud)
以下是它的使用方法:
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)
};
}
Run Code Online (Sandbox Code Playgroud)
新修饰语
在C#中使用"new"修饰符并没有完全隐藏,但它并不常见.当您需要"隐藏"基类成员而不是总是覆盖它们时,new修饰符会派上用场.这意味着当您将派生类转换为基类时,"隐藏"方法变为可见,并且在派生类中调用而不是相同的方法.
在代码中更容易看到:
public class BaseFoo
{
virtual public void DoSomething()
{
Console.WriteLine("Foo");
}
}
public class DerivedFoo : BaseFoo
{
public new void DoSomething()
{
Console.WriteLine("Bar");
}
}
public class DerivedBar : BaseFoo
{
public override void DoSomething()
{
Console.WriteLine("FooBar");
}
}
class Program
{
static void Main(string[] args)
{
BaseFoo derivedBarAsBaseFoo = new DerivedBar();
BaseFoo derivedFooAsBaseFoo = new DerivedFoo();
DerivedFoo derivedFoo = new DerivedFoo();
derivedFooAsBaseFoo.DoSomething(); //Prints "Foo" when you might expect "Bar"
derivedBarAsBaseFoo.DoSomething(); //Prints "FooBar"
derivedFoo.DoSomething(); //Prints "Bar"
}
}
Run Code Online (Sandbox Code Playgroud)
[艾德:我为双关语获得额外积分吗?对不起,无法帮助.]
文字可以用作该类型的变量.例如.
Console.WriteLine(5.ToString());
Console.WriteLine(5M.GetType()); // Returns "System.Decimal"
Console.WriteLine("This is a string!!!".Replace("!!", "!"));
Run Code Online (Sandbox Code Playgroud)
只是一点点琐事......
人们没有提到过很多东西,但它们主要与不安全的构造有关.以下是"常规"代码可以使用的代码:
选中/未选中的关键字:
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();
}
Run Code Online (Sandbox Code Playgroud)
而不是使用int.TryParse()或Convert.ToInt32(),我喜欢有一个静态整数解析函数,当它无法解析时返回null.然后我可以用?? 和三元运算符一起更清楚地确保我的声明和初始化都以易于理解的方式在一行上完成.
public static class Parser {
public static int? ParseInt(string s) {
int result;
bool parsed = int.TryParse(s, out result);
if (parsed) return result;
else return null;
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
这也有助于避免重复赋值的左侧,但更好的是避免在赋值的右侧重复长调用,例如以下示例中的数据库调用.而不是丑陋的if-then树(我经常遇到):
int x = 0;
YourDatabaseResultSet data = new YourDatabaseResultSet();
if (cond1)
if (int.TryParse(x_input, x)){
data = YourDatabaseAccessMethod("my_proc_name", 2, x);
}
else{
x = -1;
// do something to report "Can't Parse"
}
}
else {
x = y;
data = YourDatabaseAccessMethod("my_proc_name",
new SqlParameter("@param1", 2),
new SqlParameter("@param2", x));
}
Run Code Online (Sandbox Code Playgroud)
你可以做:
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));
Run Code Online (Sandbox Code Playgroud)
更清洁,更容易理解
Math.Max和Min检查边界:我在很多代码中都看到了这个:
if (x < lowerBoundary)
{
x = lowerBoundary;
}
Run Code Online (Sandbox Code Playgroud)
我觉得这个更小,更干净,更可读:
x = Math.Max(x, lowerBoundary);
Run Code Online (Sandbox Code Playgroud)
或者您也可以使用三元运算符:
x = ( x < lowerBoundary) ? lowerBoundary : x;
Run Code Online (Sandbox Code Playgroud)
Mixins是一个很好的功能.基本上,mixins让你有一个接口而不是类的具体代码.然后,只需在一堆类中实现该接口,您就可以自动获得mixin功能.例如,要将深度复制混合到多个类中,请定义一个接口
internal interface IPrototype<T> { }
Run Code Online (Sandbox Code Playgroud)
添加此接口的功能
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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后实现任何类型的接口以获得mixin.
(我刚刚使用了这个)将字段设置为null并返回它而没有中间变量:
try
{
return _field;
}
finally
{
_field = null;
}
Run Code Online (Sandbox Code Playgroud)
这不是C#特有的功能,但它是一个我发现非常有用的插件.它被称为资源重构工具.它允许您右键单击文字字符串并将其提取到资源文件中.它将搜索代码并查找匹配的任何其他文字字符串,并将其替换为Resx文件中的相同资源.
http://www.codeplex.com/ResourceRefactoring
小智 6
我称之为AutoDebug是因为您可以根据bool值直接调入调试的位置,也可以将其存储为项目用户设置.
例:
//Place at top of your code
public UseAutoDebug = true;
//Place anywhere in your code including catch areas in try/catch blocks
Debug.Assert(!this.UseAutoDebug);
Run Code Online (Sandbox Code Playgroud)
只需将上面的内容放在try/catch块或代码的其他区域中,并将UseAutoDebug设置为true或false,并在您希望进行测试时随时进入调试.
您可以保留此代码并在测试时打开和关闭此功能,您也可以将其保存为项目设置,并在部署后手动更改它,以便在/如果需要时从用户那里获取其他错误信息.
您可以在此Visual Studio C#项目模板中看到使用此技术的功能和实际示例,其中大量使用它:
http://code.msdn.microsoft.com/SEHE
方法组并不为人所知.
鉴于:
Func<Func<int,int>,int,int> myFunc1 = (i, j) => i(j);
Func<int, int> myFunc2 = i => i + 2;
Run Code Online (Sandbox Code Playgroud)
你可以这样做:
var x = myFunc1(myFunc2, 1);
Run Code Online (Sandbox Code Playgroud)
而不是这个:
var x = myFunc1(z => myFunc2(z), 1);
Run Code Online (Sandbox Code Playgroud)
我对这个问题这么迟,但我想补充一些我认为没有涵盖的问题.这些不是C#特定的,但我认为对于任何C#开发人员来说都值得一提.
DefaultValueAttribute,但不是提供属性默认的值,而是提供属性用于决定是否从其他位置请求其值的值.例如,对于WinForms中的许多控件,它们ForeColor和BackColor属性都有一个AmbientValue,Color.Empty以便他们知道从父控件中获取颜色.
使用扩展方法,标记枚举使用可以更具可读性.
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);
}
Run Code Online (Sandbox Code Playgroud)
这使得检查标志值很好并且易于读写.当然,如果我们可以使用泛型并强制使用T作为枚举会更好,但这是不允许的.也许dynamic会让这更容易.
我发现令人难以置信的是编译器通过糖代码使用外部变量会遇到什么样的麻烦:
string output = "helo world!";
Action action = () => Console.WriteLine(output);
output = "hello!";
action();
Run Code Online (Sandbox Code Playgroud)
这实际上打印hello!.为什么?因为编译器为委托创建了一个嵌套类,所有外部变量都有公共字段,并且在每次调用委托之前插入设置代码:)以上是代码'reflectored':
Action action;
<>c__DisplayClass1 CS$<>8__locals2;
CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.output = "helo world!";
action = new Action(CS$<>8__locals2.<Main>b__0);
CS$<>8__locals2.output = "hello!";
action();
Run Code Online (Sandbox Code Playgroud)
我觉得很酷.
我无法弄清楚Convert类中的某些函数有什么用(例如Convert.ToDouble(int),Convert.ToInt(double)),直到我将它们与Array.ConvertAll:
int[] someArrayYouHaveAsInt;
double[] copyOfArrayAsDouble = Array.ConvertAll<int, double>(
someArrayYouHaveAsInt,
new Converter<int,double>(Convert.ToDouble));
Run Code Online (Sandbox Code Playgroud)
这避免了定义内联委托/闭包(稍微更具可读性)引起的资源分配问题:
int[] someArrayYouHaveAsInt;
double[] copyOfArrayAsDouble = Array.ConvertAll<int, double>(
someArrayYouHaveAsInt,
new Converter<int,double>(
delegate(int i) { return (double)i; }
));
Run Code Online (Sandbox Code Playgroud)
可以为枚举定义数据类型:
enum EnumName : [byte, char, int16, int32, int64, uint16, uint32, uint64]
{
A = 1,
B = 2
}
Run Code Online (Sandbox Code Playgroud)
C#中的指针.
它们可用于执行就地字符串操作.这是一个不安全的功能,因此unsafe关键字用于标记不安全代码的区域.另请注意固定关键字如何用于指示指向的内存是固定的,并且不能由GC移动.这是指向内存地址的指针必不可少的,GC可以将内存移动到不同的地址,否则会导致指针无效.
string str = "some string";
Console.WriteLine(str);
unsafe
{
fixed(char *s = str)
{
char *c = s;
while(*c != '\0')
{
*c = Char.ToUpper(*c++);
}
}
}
Console.WriteLine(str);
Run Code Online (Sandbox Code Playgroud)
我不会这样做,只是为了这个问题来展示这个功能.
小智 6
我特别喜欢可以为空的DateTime.因此,如果你有一些日期给出的情况和其他没有给出日期的情况,我认为这是最好的使用和恕我直言,更容易理解为使用DateTime.MinValue或其他任何事情......
DateTime? myDate = null;
if (myDate.HasValue)
{
//doSomething
}
else
{
//soSomethingElse
}
Run Code Online (Sandbox Code Playgroud)
开放式泛型是另一个方便的功能,尤其是在使用控制反转时:
container.RegisterType(typeof(IRepository<>), typeof(NHibernateRepository<>));
Run Code Online (Sandbox Code Playgroud)
仔细阅读了所有9页,我觉得我必须指出一些未知的特征......
这适用于.NET 1.1,在gzip压缩文件上使用压缩/解压缩,其中一个必须:
它未被充分利用,我还不知道,(仍然使用ICSharpCode.ZipLib,即使使用.NET 2/3.5)它是在System.IO.Compression命名空间中被合并到标准BCL版本2中. .请参阅MSDN页面" GZipStream类 ".
从匿名方法访问局部变量允许您使用新的控制流逻辑包装任何代码,而不必将该代码分解为另一种方法.在方法内部声明的局部变量在方法中可用endOfLineChar,例如此处示例中的局部变量:
http://aaronls.wordpress.com/2010/02/02/retrying-on-exception-conditionally/
想到反射Emit和表达树......
不要错过Jeffrey Richter通过C#和Jon Skeet的CLR 
在这里查看一些资源:
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
在使用linqxml时,我发现这项技术很有趣:
public bool GetFooSetting(XElement ndef){
return (bool?)ndef.Element("MyBoolSettingValue") ?? true;
}
Run Code Online (Sandbox Code Playgroud)
而不是:
public bool GetFooSetting(XElement ndef){
return ndef.Element("MyBoolSettingValue") != null ? bool.Parse(ndef.Element("MyBoolSettingValue") ) : true;
}
Run Code Online (Sandbox Code Playgroud)
小智 5
通用事件处理程序:
public event EventHandler<MyEventArgs> MyEvent;
Run Code Online (Sandbox Code Playgroud)
这样您就不必一直声明自己的代理,
我没有发现 - 近一年 - 强类型DataRows包含一个Is [ColumnName] Null()方法.
例如:
Units.UnitsDataTable dataTable = new Units.UnitsDataTable();
foreach (Units.UnitsRow row in dataTable.Rows)
{
if (row.IsPrimaryKeyNull())
//....
if (row.IsForeignKeyNull())
//....
}
Run Code Online (Sandbox Code Playgroud)
构造链是否已被引用?
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()) {
}
}
}
Run Code Online (Sandbox Code Playgroud)
...
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();
Run Code Online (Sandbox Code Playgroud)
C#中指针的固定 /功能 - 这个主题太大了,但我只是简单介绍一下.
在C我们有装载结构的设施,如...
struct cType{
char type[4];
int size;
char name[50];
char email[100];
}
cType myType;
fread(file, &mType, sizeof(mType));
Run Code Online (Sandbox Code Playgroud)
我们可以在"unsafe"方法中使用fixed关键字来读取字节数组对齐的结构.
[Layout(LayoutKind.Sequential, Pack=1)]
public unsafe class CType{
public fixed byte type[4];
public int size;
public fixed byte name[50];
public fixed byte email[100];
}
Run Code Online (Sandbox Code Playgroud)
方法1(从常规流读取到字节缓冲区并将字节数组映射到struct的各个字节)
CType mType = new CType();
byte[] buffer = new byte[Marshal.SizeOf(CType)];
stream.Read(buffer,0,buffer.Length);
// you can map your buffer back to your struct...
fixed(CType* sp = &mType)
{
byte* bsp = (byte*) sp;
fixed(byte* bp = &buffer)
{
for(int i=0;i<buffer.Length;i++)
{
(*bsp) = (*bp);
bsp++;bp++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
方法2,你可以映射Win32 User32.dll的ReadFile直接读取字节...
CType mType = new CType();
fixed(CType* p = &mType)
{
User32.ReadFile(fileHandle, (byte*) p, Marshal.SizeOf(mType),0);
}
Run Code Online (Sandbox Code Playgroud)
我喜欢使用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>();
*/
Run Code Online (Sandbox Code Playgroud)
这对于代码维护也非常方便.如果您需要更改类名,则只需要更改一个位置.另一个例子:
using FloatValue = float; // you only need to change it once to decimal, double...
....
FloatValue val1;
...
Run Code Online (Sandbox Code Playgroud)
我没有看到这个:
for (;;);
Run Code Online (Sandbox Code Playgroud)
同样的
while (true) ;
Run Code Online (Sandbox Code Playgroud)
我刚刚学到的一个问题是你仍然可以在一个可以为空的值上调用方法 ....
当你有一个可以为空的值时,结果是什么:
decimal? MyValue = null;
Run Code Online (Sandbox Code Playgroud)
您可能认为必须写的地方:
MyValue == null ? null : MyValue .ToString()
Run Code Online (Sandbox Code Playgroud)
你可以写:
MyValue.ToString()
Run Code Online (Sandbox Code Playgroud)
我已经知道我可以调用MyValue.HasValue和MyValue.Value ......但它没有完全点击我可以调用ToString().
这不会编译:
namespace ns
{
class Class1
{
Nullable<int> a;
}
}
Run Code Online (Sandbox Code Playgroud)
找不到类型或命名空间名称'Nullable'(您是否缺少using指令或程序集引用?) < - missing' using System;'
但
namespace ns
{
class Class1
{
int? a;
}
}
Run Code Online (Sandbox Code Playgroud)
会编译!(.NET 2.0).
如果有人提到这个,我道歉,但我经常使用它.
Visual Studio的加载项由Alex Papadimoulis开发.它用于将常规文本粘贴为字符串,字符串构建器,注释或区域.
在这个插件中(我也不知道是否已经提到过)我注意到字符串是用字符串文字前缀粘贴的:
@
Run Code Online (Sandbox Code Playgroud)
我知道这些,但我不知道在文字中使用双引号来逃避引用.
例如
string s = "A line of text" + Environment.NewLine + "Another with a \"quote\"!!";
Run Code Online (Sandbox Code Playgroud)
可以表达为
string s = @"A line of text
Another with a ""quote""!!";
Run Code Online (Sandbox Code Playgroud)
我喜欢EditorBrowsableAttribute.它允许您控制是否在Intellisense中显示方法/属性.您可以将值设置为"始终","高级"或"从不".
来自MSDN ......
备注
EditorBrowsableAttribute是设计器的提示,指示是否要显示属性或方法.您可以在可视化设计器或文本编辑器中使用此类型来确定用户可见的内容.例如,Visual Studio中的IntelliSense引擎使用此属性来确定是否显示属性或方法.
在Visual C#中,您可以在"工具"下的"智能感知"和"属性"窗口中使用"隐藏高级成员"设置控制何时显示高级属性 选项| 文字编辑器| C#.相应的EditorBrowsableState为Advanced.
__arglist也是
[DllImport("msvcrt40.dll")]
public static extern int printf(string format, __arglist);
static void Main(string[] args)
{
printf("Hello %s!\n", __arglist("Bart"));
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
...然后我可以通过在我的自定义缓存管理器中使用以下内容来大大简化我的缓存获取/设置代码
public static IUser CurrentUser
{
get
{
return CachePattern<IUser>("CurrentUserKey", () => repository.NewUpUser());
}
}
Run Code Online (Sandbox Code Playgroud)
现在,简单的"日常"代码模式可以编写一次,并且可以更轻松地重复使用恕我直言.我不必编写委托类型并弄清楚我想如何实现回调等.如果我能在10秒内写出来,那我就不那么贴切了.求助于剪切/粘贴简单的代码模式,无论它们是惰性初始化还是上面显示的其他一些例子......
允许带有大括号的空块.
你可以写这样的代码
{
service.DoTonsOfWork(args);
}
Run Code Online (Sandbox Code Playgroud)
当你想要在没有using或try... finally已经写过的情况下尝试某些东西时,它会很有用.
//using(var scope = new TransactionScope)
{
service.DoTonsOfWork(args);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
681557 次 |
| 最近记录: |