1472
votes

This came to my mind after I learned the following from this question:

where T : struct

We, C# developers, all know the basics of C#. I mean declarations, conditionals, loops, operators, etc.

Some of us even mastered the stuff like Generics, anonymous types, lambdas, LINQ, ...

But what are the most hidden features or tricks of C# that even C# fans, addicts, experts barely know?

Here are the revealed features so far:


Keywords

Attributes

Syntax

Language Features

Visual Studio Features

Framework

Methods and Properties

Tips & Tricks

  • Nice method for event handlers by Andreas H.R. Nilsson
  • Uppercase comparisons by John
  • Access anonymous types without reflection by dp
  • A quick way to lazily instantiate collection properties by Will
  • JavaScript-like anonymous inline-functions by roosteronacid

Other

0

296 Answers 296

1 2 3
4
5
10
21
votes

Another note on event handlers: you can simply create a raise extension method like so:

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

Then you can use it to raise events:

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

This method has the added advantage of enforcing a coding standard (using EventHandler<>).

There isn't a point in writing the same exact function over and over and over again. Perhaps the next version of C# will finally have an InlineAttribute that can be placed on the extension method and will cause the compiler to inline the method definition (which would make this way nearly standard, and the fastest).

edit: removed temp variable inside extension method based on comments

3
  • You don't need the temp variable. It's used for avoiding an async change, but the event parameter is sufficient for that.
    – jpbochi
    Commented Jun 23, 2010 at 2:08
  • I am not so sure about that. The parameter is a reference type, so @event is the same object as the event in the class (unless there is something going on with the event syntax that I don't know about). Being that the assignment and checking code is recommended practice, I expect that the assignment operator is defined here to get around this problem. Regardless, it doesn't hurt to be safe.
    – Bill Barry
    Commented Jun 23, 2010 at 13:04
  • jpbochi is right, the temp variable does nothing. The parameter is a reference type, that's right but it's not passed by reference and there's a huge difference. Also, this extension works only for events using the the generic EventHandler delegate. When the generic delegate is used it's a neat trick though. Commented Jun 30, 2010 at 18:31
21
votes

On the basis that this thread should be entitled "things you didn't know about C# until recently despite thinking you already knew everything", my personal feature is asynchronous delegates.

Until I read Jeff Richter's C#/CLR book (excellent book, everyone doing .NET should read it) I didn't know that you could call any delegate using BeginInvoke / EndInvoke. I tend to do a lot of ThreadPool.QueueUserWorkItem calls (which I guess is much like what the delegate BeginInvoke is doing internally), but the addition of a standardised join/rendezvous pattern may be really useful sometimes.

2
21
votes

Near all the cool ones have been mentioned. Not sure if this one's well known or not

C# property/field constructor initialization:

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

This creates the rectangle, and sets the listed properties.

I've noticed something funny - you can have a comma at the end of the properties list, without it being a syntax error. So this is also valid:

var foo = new Rectangle() 
{ 
    Fill = new SolidColorBrush(c), 
    Width = 20, 
    Height = 20,
};
4
  • 8
    The comma at the end makes fiddling with the values much easier :) Commented Mar 30, 2009 at 11:07
  • The trailing comma is also useful for generated code. You'll note that it holds for many situations. I run across it most often when making an enum. :)
    – Greg D
    Commented May 8, 2009 at 16:59
  • Enums also support the trailing comma "feature".
    – John B
    Commented Jun 8, 2009 at 16:27
  • 6
    You don't need the () in Rectangle() either
    – rball
    Commented Nov 11, 2009 at 23:23
20
votes

Atrribute Targets

Everyone has seen one. Basically, when you see this:

[assembly: ComVisible(false)]

The "assembly:" portion of that attribute is the target. In this case, the attribute is applied to the assembly, but there are others:

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

In this sample the attribute is applied to the return value.

0
20
votes

One great class I like is System.Xml.XmlConvert which can be used to read values from xml tag. Especially, if I am reading a boolean value from xml attribute or element, I use

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

Note: since boolean type in xml accepts 1 and 0 in addition to "true" and "false" as valid values, using string comparison in this case is error-prone.

20
votes

Apologies for posting so late, I am new to Stack Overflow so missed the earlier opportunity.

I find that EventHandler<T> is a great feature of the framework that is underutilised.

Most C# developers I come across still define a custom event handler delegate when they are defining custom events, which is simply not necessary anymore.

Instead of:

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

public class MyCustomEventClass 
{
    public event MyCustomEventHandler MyCustomEvent;
}

you can go:

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

which is a lot more concise, plus you don't get into the dilemma of whether to put the delegate in the .cs file for the class that contains the event, or the EventArgs derived class.

1
20
votes

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.

0
20
votes

OK, it may seem obvious, but I want to mention the Object.Equals method (the static one, with two arguments).

I'm pretty sure many people don't even know about it, or forget it's there, yet it can really help in some cases. For instance, when you want to compare two objects for equality, not knowing if they're null. How many times did you write something like that :

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

When you can just write :

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

(Object.Equals is actually implemented exactly like in the first code sample)

0
20
votes
string.Empty

I know it's not fantastical (ludicrously odd), but I use it all the time instead of "".

And it's pretty well hidden until someone tells you it's there.

13
  • 4
    @Arnos: It is not about beying short; it is about maintainability: understanding the meaning of something 2 months after you wrote some code. In stead of wondering where "" actually meant " " (and forgotting a space) or an empty string. String.Empty is much clearer. This holds for the .Empty pattern in general: you see it in many more types. Commented Jun 30, 2010 at 9:55
  • 3
    Not exactly hidden if you know a little bit about the framework. Commented Jun 30, 2010 at 11:26
  • 3
    This is one of things you get religious arguments about: string.Empty vs "" - personally I find the latter much easier to read, and it makes no different to the compiled code.
    – Keith
    Commented Jun 30, 2010 at 11:58
  • 3
    I find blogs.msdn.com/b/ericlippert/archive/2009/09/28/… to be of interest. It points out a case where "" and string.Empty will not have the same behavior during == comparisons.
    – Brian
    Commented Jun 30, 2010 at 18:44
  • 3
    String.Empty is .NET, not C#. It is accessible from any syntax on the .NET framework.
    – John K
    Commented Jul 1, 2010 at 2:56
20
votes

I'm late to this party, so my first choices are already taken. But I didn't see anyone mention this gem yet:

Parallel Extensions to the .NET Framework

It has things like replace with Parallel.For or foreach with Parallel.ForEach


Parallel Sample :
In your opinion, how many CLR object can be created in one second? enter image description here
See fallowing example :

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);
       }
   }
}
1
  • It is not really a language feature, though, as it is just a library which uses other language features cleverly. Commented Sep 21, 2008 at 17:41
19
votes

C# 3.0's LINQ query comprehensions are full-blown monadic comprehensions a la Haskell (in fact they were designed by one of Haskell's designers). They will work for any generic type that follows the "LINQ pattern" and allows you to write in a pure monadic functional style, which means that all of your variables are immutable (as if the only variables you used were IDisposables and IEnumerables in using and foreach statements). This is helpful for keeping variable declarations close to where they're used and making sure that all side-effects are explicitly declared, if there are any at all.

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

 }
0
19
votes

I see a lot of people replicate the functionality of Nullable<T>.GetValueOrDefault(T).

4
  • In my opinion, ?? is cleaner in most cases, at least for primitive types (a ?? 0 instead of a.GetValueOrDefault()). The added burden of supplying the actual default value vanishes when you actually want another value. Commented Mar 30, 2009 at 12:36
  • @OregonGhost: GetValueOrDefault (with or without a default value supplied) is about 33% faster than ??, although in truth, you won't notice a difference unless you do millions of iterations.
    – P Daddy
    Commented Jun 15, 2009 at 3:16
  • 1
    @P Daddy: I tried to benchmark myself: GetValueOrDefault seems only to be 33% faster in Debug builds. In Release builds both are about the same.
    – helium
    Commented Dec 25, 2009 at 12:46
  • 1
    I do this: var x = Nullable<X> ?? MyPreferedDefaultValue; Commented Jun 3, 2011 at 18:33
19
votes

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 
}
11
  • 2
    Can you explain this? Not sure I follow how this works or what it does
    – Dan
    Commented Jun 22, 2010 at 13:16
  • 2
    It's just shifting the bits in the binary representation of the number, 0001 << 1 becomes 0010, 0001 << 2 becomes 0100, 0001 << 3 becomes 1000
    – CaffGeek
    Commented Jun 22, 2010 at 13:32
  • 5
    Interesting, but anyone who doesn't immediately recognize the pattern 0,1,2,4,8...16384,32768... probably shouldn't be reading the code, and almost certainly won't know that 1 << 2 == 4.
    – ScottS
    Commented Jun 22, 2010 at 15:30
  • 5
    FlagsAttribute alone should make one realize that enum is a bit field. IMO shifting bits in enum definition is not for readability but for lazies, who don't bother remembering the power of two values ;)
    – Aoi Karasu
    Commented Jun 23, 2010 at 4:32
  • 19
    @AOIKarasu- C# itself is for lazies who can't be bothered with lower level languages. Lower level languages are for lazies who can't be bother with Assembler. Assembler is for lazies who can't be bothered typing in binary. Typing is for lazies who can't be bothered etching tiny dots on a hard disk.Hard disks are for lazies who can't be bothered with punch cards. Punch cards are for lazies who can't be bothered scribing on paper. Paper is for lazies who can't be bothered etching on stone tablets. I'm in all of those varieties of lazy! :) Bit 9 is still easer to read as 1 << 9 than 512. YMMV!
    – Steve Dunn
    Commented Jun 23, 2010 at 6:45
18
votes

My favorite attribute: InternalsVisibleTo

At assembly level you can declare that another assembly can see your internals. For testing purposes this is absolutely wonderful.

Stick this in your AssemblyInfo.cs or equivalent and your test assembly get full access to all the internal stuff that requires testing.

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

As you can see, the test assembly must have a strong name to gain the trust of the assembly under test.

Available in .Net Framework 2.0+, Compact Framework 2.0+ and XNA Framework 1.0+.

2
  • 3
    Yeah, great for test assemblies... And only test assemblies. Right? ;)
    – JohannesH
    Commented Aug 3, 2009 at 12:19
  • @JohannesH - Yes, I would agree. There is a good reason for having the internal keyword, and that is to keep things internal :) Commented Aug 3, 2009 at 18:10
17
votes

I love using the @ character for SQL queries. It keeps the sql nice and formatted and without having to surround each line with a string delimiter.

string sql = @"SELECT firstname, lastname, email
               FROM users
               WHERE username = @username AND password = @password";
6
  • I use '@' all the time, but I never thought of spanning multiple lines! :-P Commented Oct 27, 2008 at 5:23
  • 4
    One minor gripe with this (in this scenario) is that the spaces used for indenting and the newline characters end up in the string. Not generally a problem but one to be aware of.
    – BlackWasp
    Commented Jan 3, 2009 at 17:45
  • 17
    Another problem is that you're writing SQL in code :( Commented Mar 25, 2009 at 20:37
  • 1
    I agree, its often not a good idea to write raw SQL like this, but its not always possible to get away from SQL code. Besides, it is just an example.
    – Nathan Lee
    Commented Mar 26, 2009 at 4:21
  • 2
    The SQL uses parameters. Apart from the SQL itself being hardcoded, I don't see any problems. Commented Jun 14, 2010 at 9:31
17
votes

The extern alias keyword to reference two versions of assemblies that have the same fully-qualified type names.

17
votes

Need to return an empty IEnumerable?

public IEnumerable<T> GetEnumerator(){
  yield break;
}
5
  • 9
    Already in the BCL System.Linq.Enumerable.Empty<T>()
    – chakrit
    Commented Feb 25, 2010 at 8:18
  • 2
    @chak Which is a wrapper around return new T[0];. There are many ways to do this. This is but just one. But it is an interesting one...
    – user1228
    Commented Feb 25, 2010 at 15:28
  • 5
    This one is a little opaque for my tastes, I prefer chakrit's solution. Commented Mar 19, 2010 at 1:29
  • Actually, it's a wrapper around a static instance of T[], so new T[0] is only called once per type.
    – phoog
    Commented Nov 25, 2010 at 6:44
  • @Alex: I'd prefer yield break in a generator function (i.e. which also yield returns) I'd use Enumerable.Empty everywhere else
    – sehe
    Commented Mar 23, 2011 at 23:06
17
votes

You can limit the life and thus scope of variables by using { } brackets.

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

Console.Write(test2); //compile error

test2 only lives within the brackets.

3
  • 2
    This is true of C++ too.
    – ChrisF
    Commented Sep 27, 2009 at 20:33
  • True of any language with lexical scoping no? Commented Jan 8, 2012 at 21:46
  • hmmm...Is this a hidden feature??
    – Kai
    Commented Jan 30, 2012 at 10:30
16
votes

Ability to use LINQ Expressions to perform strongly-typed reflection:

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'

More details are available at How to Find Out Variable or Parameter Name in C#?

1
  • +1 You can also do this with anonymous types.
    – MattDavey
    Commented Mar 6, 2012 at 14:49
16
votes

You can use any Unicode character in C# names, for example:

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

You can even use Unicode escapes. This one is equivalent to the above:

public class MyClass
{
    public string H\u00e5rføner()
    {
        return "Yes, it (still) works!";
    }
}
4
  • To anyone outside the english-speaking world, it's actually a giant leap towards language-agnostic computing. To us (to me, at least), it's actually somewhat quaint and old-fashioned to have to stick to the 26 letters of the english alphabet. A bit like 8.3 file names, you know.
    – Tor Haugen
    Commented Mar 11, 2009 at 0:41
  • 4
    Hmm, yes, let's mix English BCL identifiers and keywords with non-English identifiers. Now people from other countries can't use your code anymore without Intellisense :P ;) No. It's only consequent to be able to use any character, but there's no real benefit to it. Commented Mar 30, 2009 at 12:39
  • 1
    Although some might find this useful I think it should be avoided in our industry since we will often have several nationalities involved in a project. Also as OregonGhost mentiones it will go against existing naming in BCL and 3rd party libraries. I'm currently working on a project which didn't use english naming and we are now suffering from confusing names as well as the inability to hand over our code to our indian testers without extensive documentation and transcription of member names. Remember that code should be readable by humans... This includes humans of other nationalities.
    – JohannesH
    Commented Aug 3, 2009 at 12:13
  • +1 - I'm using the unicode Pi and Tau symbols as members in my Math class - makes code much nicer to read! float area = Math.π * (radius * radius). What I'd really like to do is define an extension method called ² so I can type float area = Math.π * radius.²();
    – MattDavey
    Commented Mar 1, 2012 at 14:21
16
votes

You can store colors in Enum.

public enum MyEnumColors : uint
{
    Normal          = 0xFF9F9F9F,
    Active          = 0xFF8EA98A,
    Error           = 0xFFFF0000
}
2
  • 3
    Yes, but what for? Why not create strongly-typed static class attributes instead? Might just as well abuse strings to store arbitrary blobs of data, instead of using classes, as was done often in BASIC. Commented Mar 11, 2010 at 15:09
  • 4
    I think FFire is trying to draw attention to the fact that you can specify the base type (in this case uint) for an enum
    – sehe
    Commented Mar 23, 2011 at 22:52
15
votes

Using "~" operator with FlagAttribute and enum
Sometime we would use Flag attribute with enum to perform bitwise manipulation on the enumeration.

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

Notice that, the value of option "All" which in enum is quite strange.
Instead of that we can use "~" operator with flagged enum.

 [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.
 }
3
  • it must be 32 i think not 31, what you say?
    – Mubashar
    Commented Apr 14, 2010 at 13:22
  • 3
    Remember that it is a flagged enum. So in this case "All" equal to (Red & Blue & White & Black & Green) then it would also equal to (00001 & 00010 & 00100 & 01000 & 10000) and equal to 11111 and equal to 31 as well. The number 32 should be 100000 but 11111. Commented Apr 14, 2010 at 14:08
  • 2
    I prefer spelling it out All = Red | Blue | White | Black | Green and e.g. Dark = Blue | Black, Light = All & ~Dark
    – sehe
    Commented Mar 23, 2011 at 22:48
15
votes

How about the FlagsAttribute on an enumeration? It allows you to perform bitwise operations... took me forever to find out how to do bitwise operations in .NET nicely.

3
  • 5
    I think you can do bitwise operations on any enum, flags only affect the ToString() method
    – Olmo
    Commented Nov 24, 2008 at 22:22
  • 10
    This is actually pretty dangerous - it doesn't have any effect on the values assigned - it's purely a marker attribute to indicate your intention, so if you don't explicitly declare your enum values as powers of two then you will think you have a bitwise enum, but you won't really...
    – user6586
    Commented Jun 30, 2009 at 11:08
  • 1
    You cannot use the Enum.HasFlag(...) method unless the Enum you're referencing has the FlagsAttribute attribute.
    – cwharris
    Commented Sep 28, 2011 at 7:07
15
votes

Also useful, but not commonly used : Constrained Execution Regions.

A quote from BCL Team blog :

Constrained execution regions (CER's) exist to help a developer write her code to maintain consistency. The CLR doesn't guarantee that the developer's code is correct, but the CLR does hoist all of the runtime-induced failure points (ie, async exceptions) to either before the code runs, or after it has completed. Combined with constraints on what the developer can put in a CER, these are a useful way of making strong guarantees about whether your code will execute. CER's are eagerly prepared, meaning that when we see one, we will eagerly JIT any code found in its statically-discoverable call graph. If the CLR's host cares about stack overflow, we'll probe for some amount of stack space as well (though perhaps not enough stack space for any arbitrary method*). We also delay thread aborts until the CER has finished running.

It can be useful when making edits to more than one field of a data structure in an atomic fashion. So it helps to have transactions on objects.

Also CriticalFinalizerObject seems to be hidden(at least who are not writing unsafe code). A CriticalFinalizerObject guarantees that garbage collection will execute the finalizer. Upon allocation, the finalizer and its call graph are prepared in advance.

1
  • Hmm... could that make aborting threads safe if they were written for it?
    – devios1
    Commented Jun 30, 2010 at 20:29
15
votes

You can add and remove delegates with less typing.

Usual way:

handler += new EventHandler(func);

Less typing way:

handler += func;
3
  • 4
    Saw that all the time... just make my hand itch :) Also, if you type += in VS and then [TAB][TAB] to generate an event handler, the delegate type is still inserted... kinda annoying.
    – chakrit
    Commented Feb 25, 2010 at 9:04
  • @sr pt: No it is not a resharper functionality. It is a default function in Visual studio (I even believe it is in there since 2005). Visual studio has more of these auto complete snippets.
    – Gertjan
    Commented Apr 6, 2010 at 13:09
  • 1
    @Aneves: Resharper lets you easily remove this extra bit of fluff though. Commented Jun 30, 2010 at 21:01
15
votes

fixed statement

This statement prevents the garbage collector from relocating a movable variable. Fixed can also be used to create fixed size buffers.

The fixed statement sets a pointer to a managed variable and "pins" that variable during the execution of statement.

stackalloc

The stackalloc allocates a block of memory on the stack.

6
  • 4
    I think this should include an example of why/how this can be useful
    – Neil N
    Commented Jun 30, 2010 at 19:38
  • 1
    @Neil You can follow the links in the answer. There you can see some examples and more details on remarks section. Tell me if that will not be satisfying I'll update the answer with example code.
    – Incognito
    Commented Jul 1, 2010 at 4:11
  • 1
    Code formatting and links don't mix well; it's not immediately obvious that the keywords are links as well. But of course, the links are relevant, once you find them :-)
    – Zano
    Commented Jul 2, 2010 at 19:17
  • @Zano code formating is removed. Hope it is easy to notice links now.
    – Incognito
    Commented Jul 10, 2010 at 19:28
  • What has not been mentioned so far, for people that started learning programming with a GC: stack allocation is basically just an incrementation of the stack pointer and is therefore, well, let's call it "really fast". ;-) since there will be a stack allocated for the running function, anyways, i guess that the stackalloc memory is just added when doing that allocation, therefore making it a no-op without any runtime penalties at all. That's just my guess, though. Commented Feb 25, 2011 at 6:38
15
votes

I have often come across the need to have a generic parameter-object persisted into the viewstate in a base class.

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

}

Usage:

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

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

This little trick with the "where ParameterType : BaseParameterType, new" is what makes it really work.

With this property in my baseclass, I can automate handling of paging, setting filter values to filter a gridview, make sorting really easy, etc.

I am really just saying that generics can be an enormously powerful beast in the wrong hands.

4
  • Maybe I'm being daft, but I'm not sure I understand the code. Could you post a more complete example? Commented Apr 23, 2009 at 11:18
  • 1
    Its pretty simple actually. If you have a GridView with a couple of DropDownLists to filter out content, you just put the values into your filter object that is persisted between postbacks, and send it as a parameter to the method that fetches data from the DB. You would just implement your UserControl inheriting from BaseListControl, and the base takes care of persisting "state" between postbacks. Commented Apr 23, 2009 at 14:22
  • 1
    what do you mean "little trick"? Are you referring to the fact that you can't create a parameterised type inside a generic unless the generic constraints contains a "new" clause?
    – Andy Dent
    Commented Oct 3, 2009 at 23:19
  • No, the little trick is constraining to BaseParameterType. A bit of a typo :\ Commented Oct 7, 2009 at 7:57
14
votes

Labeling my endregions...

#region stuff1
 #region stuff1a
 //...
 #endregion stuff1a
#endregion stuff1
0
14
votes

ConditionalAttribute

Allows you to tell the compiler to omit the call to the method marked with the attribute under certain conditions (#define).

The fact that the method call is omitted also means that its parameters are not evaluated. This is very handy and it's what allows you to call expensive validation functions in Debug.Assert() and not worry about them slowing down your release build.

14
votes

When defining custom attributes you can use them with [MyAttAttribute] or with [MyAtt]. When classes exist for both writings, then a compilation error occures.

The @ special character can be used to distinguish between them:

[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 {}
1
  • Of course, the best solution is to fix one or both names so they don't clash in the first place. But this is good to know in case of dealing with third-party libraries that did it wrong, and that you can't fix.
    – Ryan Lundy
    Commented Jan 22, 2010 at 14:48
1 2 3
4
5
10

Not the answer you're looking for? Browse other questions tagged or ask your own question.