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

where T : struct

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

我们中的一些人甚至掌握了Generics、匿名类型、lambdas、LINQ等等。。。

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

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

关键词

迈克尔·斯图姆的产量Michael Stum的varkokos的using()语句kokos只读由Mike Stone作者:Ed Swangren由Rocketpants改进因死亡而违约全球::由pzycomanAlexCuse的using()块Jakubšturc的挥发性Jakubšturc的外部别名

属性

Michael Stum的DefaultValueAttributeDannySmurf的ObsoleteAttribute调试器DisplayAttribute(按Stu)bdukes提供的DebuggerBrowseble和DebuggerStepThroughmarxidad的ThreadStaticAttributeMartin Clarke的FlagsAttributeAndrewBurns的ConditionalAttribute

语法

?? kokos的(合并空值)运算符Nick Berardi的数字标记其中T:Lars Mæhlum的新Keith的隐式泛型Keith的单参数lambdas基思汽车财产Keith的命名空间别名Patrick的带@的逐字字符串文字按lfoost列出的枚举值@marxidad的variableamesmarxidad的事件运算符由Portman设置字符串括号格式xanadot的属性访问器可访问性修饰符JasonS的条件(三元)运算符(?:)Binoj Antony检查和未检查操作员Flory的隐式和显式运算符

语言功能

Brad Barker的可空类型Keith的匿名类型__由Judah Himango制作的makeref __reftype __refvaluelomaxx的对象初始化器达科他州David的字符串格式marxidad的扩展方法Jon Erickson的部分方法John Asbeck的预处理器指令Robert Durgin的DEBUG预处理器指令SefBkn导致操作员过载通过chakrit推断类型Rob Gough将布尔运算符提升到下一级通过Roman Boiko将值类型变量作为不带装箱的接口传递由Roman Boiko编程确定声明的变量类型Chris的静态构造器使用LINQ by roosteronacid更容易进行眼睛/精简ORM映射__Zac Bowling的arglist

Visual Studio功能

Himadri在编辑器中选择文本块DannySmurf的片段

框架

KiwiCastard的TransactionScopeKiwiAstard的从属事务IainMH的<T>可为空迪亚戈的Mutex按ageektrapped列出的System.IO.PathJuan Manuel的WeakReference

方法和财产

KiwiAstard的String.IsNullOrEmpty()方法KiwiCastard的List.ForEach()方法Will Dean的BeginInvoke()、EndInvoke(()方法Nullable<T>。HasValue和Nullable<T>。Rismo的Value财产John Sheehan的GetValueOrDefault方法

提示和技巧

Andreas H.R.Nilsson的事件处理程序的好方法John的大写比较访问匿名类型而不通过dp进行反射Will延迟实例化集合财产的快速方法chosteronacid提供的类似JavaScript的匿名内联函数

另外

kokos的netmodulesDuncan Smart的LINQBridgeJoel Coehorn的并行扩展


当前回答

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

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

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

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

其他回答

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

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

变成

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

在.NET 3.5中与lambdas语句一起使用时,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#最接近可选参数。

仅适用于使用扩展方法的引用枚举二进制操作。

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

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

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

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

当你可以写:

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

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

在包含转义字符的字符串之前使用@。基本上,当使用物理路径在字符串变量中赋值时,每个人都会在字符串中出现转义符时使用“\”。

例如string strPath=“D:\websites\web1\images\”;

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

例如string strPath=@“D:\websites\web1\images\”;