57

One of the common programming best practices is "define variables as close to where they are used as possible".

I use structs frequently to create code thats almost self documenting in places. However, C# forces me to define the struct outside the method. This breaks the aforementioned best practice - its basically creating an unwanted global variable type for the entire class.

Is it possible to define a local struct inside a method, just like a local variable, and if not, could you give me a window into the reasons the C# designers decided to prevent this?

Use Case

I'm converting part of a spreadsheet into C# code. I'd like to use local structs within the method to store temporary information in an organized manner, without having to resort to hundreds of separate variables that are global in scope.


Update 2016-August: C# 7.0 may have this feature!

As of 2016-Aug, apparently, this will be a feature in C# 7.0.

So the C# compiler team agreed - wow!


Update 2020-July: Now supported by C# and C++

C++ has always fully supported this. And it's fantastic.

C# 7.0 now has value tuples for a lightweight data structure with named fields. See answer from Ghost4Man.

Contango
  • 76,540
  • 58
  • 260
  • 305
  • 1
    Are you talking about the struct declaration, or a specific instance of that struct? – Joe Nov 17 '10 at 15:25
  • Maybe anonymous types can help you or Tuple<>? C# Anonymous types: the Basics http://bit.ly/dpH6io But Im not sure what you try to achieve. Maybe you can show example of fake declaration as you want it. – Nick Martyshchenko Nov 17 '10 at 15:27
  • @Joe - I'm talking about a static declaration of a struct, together with a specific instance, so I can store the results of temporarily calculations in an organized way. For the curious, I'm converting part of a spreadsheet to C# code. – Contango Nov 17 '10 at 15:31
  • @Gravitas -- You mentioned that the struct was 'static' in your last comment. Why are you declaring a static struct inside of a method? Is that method also static? Possibly that's the real issue... hmm? Since we're not in C++ anymore, why not just stick to convention and declare a private member for the method that you're constructing to utilize locally? – Hardryv Nov 17 '10 at 15:52
  • 2
    @Hardryv Unfortunately, C# does not support defining local structs within a method, static or otherwise. Its a pity, as it'd be nice to use Intellisense when storing the results of temporary calculations within a method. A local struct would also allow me to organize the results of temporary calculations, and as the struct is local to the method it doesn't seem necessary to define it outside the method. Oh well, C# is 99.99% perfect so I guess I can't complain :) – Contango Nov 19 '10 at 12:23
  • @Gravitas -- Understood. I suppose it didn't translate well enough in my comment but I was actually proposing using an available type option vice an actual struct (I know of the limitations you cited). Based on voting, it looks as though you found a way to accomplish your goals using anonymous types, so congratulations ;). – Hardryv Nov 22 '10 at 18:31
  • Any update on this? Does C# support this now? – Paiman Roointan Jul 07 '20 at 16:19
  • 1
    @PaimanRoointan No. Unfortunately, C# does not support local structs, so that feature never made it in. However, C++ does, and it's fantastic. Updated the question to note. – Contango Jul 09 '20 at 07:34

9 Answers9

31

I believe it's not permitted to define named types within a method. As to why, I'll have to speculate. If a type is not going to be used outside, then its existence probably cannot be justified.

You can however define anonymous type variables within a method. It will somewhat resembles structures. A compromise.

public void SomeMethod ()
{
    var anonymousTypeVar = new { x = 5, y = 10 };
}
  • 9
    I can think of many cases where you would use a struct in just one method -- a complicated LINQ query, for example, where you may not want a large result set to incur GC stress. Structs can be an elegant way around that. – cdhowie Nov 17 '10 at 15:28
  • 11
    Also, anonymous types are classes, not structs. – cdhowie Nov 17 '10 at 15:28
  • 1
    With LINQ the practice is to use anonymous types which can be seen as a substitute for structs. Not quite the same but close. –  Nov 17 '10 at 15:29
  • 4
    Close yes, but I can see if someone wanted to optimize a query that was causing the GC too much stress, structs could be an attractive alternative. (I don't think this is what the OP wants to do, just pointing out that it is a legitimate use of a struct type inside one method only.) – cdhowie Nov 17 '10 at 15:30
  • Unfortunately, this won't work as the struct is readonly, and you can't reassign values to variables after you've defined anonymousTypeVar (which is what I was aiming to do in the main question). I guess I'll just have to stick to defining the struct outside of the method. – Contango Nov 19 '10 at 12:17
  • Yes, you are correct. Anonymous type variables are read-only. –  Nov 19 '10 at 12:34
14

It is a little late but this is my solution for lists - using anonymous vars as the structs inside of methods:

var list = new[] { new { sn = "a1", sd = "b1" } }.ToList(); // declaring structure
list.Clear();                                               // clearing dummy element
list.Add(new { sn="a", sd="b"});                            // adding real element
foreach (var leaf in list) if (leaf.sn == "a") break;       // using it

Anonymous elements (sn and sd) are somehow read only.

Ildar
  • 141
  • 1
  • 2
11

Since C# 7.0, you can use value tuples if you want a lightweight data structure with named fields. They can be used not only locally inside methods, but also in parameters, returns, properties, fields, etc. You can use local functions to somewhat emulate struct methods.

var book = (id: 65, pageCount: 535);        // Initialization A
(int id, int pageCount) book2 = (44, 100);  // Initialization B
Console.WriteLine($"Book {book.id} has {book.pageCount} pages.");

(int id, int pageCount) = book;  // Deconstruction into variables
Console.WriteLine($"Book {id} has {pageCount} pages.");

Here book is of type System.ValueTuple<int, int> (a generic struct).

Ghost4Man
  • 1,040
  • 1
  • 12
  • 19
  • Brilliant, I was not aware of that. Thanks! Corrected my answer above and updated to refer to yours. – Contango Jul 15 '20 at 20:15
6

You could do something like this using anonymous types. MSDN examples below:

var v = new { Amount = 108, Message = "Hello" };

or

var productQuery = 
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}
Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • 2
    Unfortunately, this won't work if you want to reassign values to variables after you've defined in v, which is what I was aiming to do in the main question. I guess I'll just have to stick to defining the struct outside of the method. – Contango Nov 19 '10 at 12:18
  • Yes, there's no direct way to do exactly what you wanted. – Steve Townsend Nov 19 '10 at 13:57
3

Nowadays, you could also use a named tuple: https://learn.microsoft.com/en-us/dotnet/csharp/tuples

Pang
  • 9,564
  • 146
  • 81
  • 122
  • I gotta say, welcome to Stack overflow! You are absolutely correct, a tuple does an equivalent job to a local struct or a class. – Contango Oct 22 '19 at 09:41
2

No, this is not possible. If you are using .net 4.0, you could use Tuple<T1, ..., Tn> to replicate such a thing.

I don't see the reason why you would need such a struct - just use variables with speaking names and this shouldn't be any problem at all. In combination with explicit declaration using the class names there is very little space for ambiguity.

Femaref
  • 60,705
  • 7
  • 138
  • 176
  • 1
    Ok - I'm curious as to why the C# designers prevented this? – Contango Nov 17 '10 at 15:25
  • 2
    And the `Tuple<...>` types are classes, not structs. – cdhowie Nov 17 '10 at 15:26
  • 2
    @Gravitas: Because there is really no benefit to doing so. Just define the struct immediately prior to the method. That will keep them logically grouped in your code. (Use a `#region` too, if you feel like it.) – cdhowie Nov 17 '10 at 15:26
  • That's why I said "replicate". I don't see the reason for such a struct anyway, as C# is a strongly typed language, together with explicit declaration of speaking-name variables there shouldn't be the need for such a thing. – Femaref Nov 17 '10 at 15:27
  • 4
    @Gravitas: They didn't so much "prevent" it as "not include it as a possible feature". Don't forget that every feature has a design, implementation and testing cost - as well as making the language more complex for everyone to learn. – Jon Skeet Nov 17 '10 at 15:29
  • Keep in mind that, as with anonymous types, Tuple properties, Item1, Item2, etc. are read-only, at least as late as C# 5. – Kelly Cline Sep 12 '16 at 18:51
  • If you use multiple of such thing placed on such thing, you need this. – Xwtek May 08 '20 at 00:09
1

You can define an anonymous type within your method and use it. The anonymous type will be readonly, so it gets you the immutability that is desired of structs. It will not explicitly be a struct, but it will be fully defined and contained within your method.

var myLocalType = new 
    {
        SomeValue = "Foo",
        SomeId = 14
    };
Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
1

it's not a struct, but mayme a var can help you out here?

var person = new {Name= "John", City = "London"};

it's strong typed so it will be compile time checked

Michel
  • 23,085
  • 46
  • 152
  • 242
  • Unfortunately, this won't work if you want to reassign values to variables after you've defined person, which is what I was aiming to do in the main question. I guess I'll just have to stick to defining the struct outside of the method. – Contango Nov 19 '10 at 12:19
1

You can create a dynamic type in c# 4.0 to accomplish this task, but its not exactly what you are looking for.

However I believe that the maximum of defining variables as close to where they are used is meant to mean where a variable is introduced into program flow not where the type is declared. I believe that most types have some ability to be reused creating in method types limits you ability to create reusable blocks of code that operates on common data.

rerun
  • 25,014
  • 6
  • 48
  • 78