I've started programming in C# to develop some console applications and I was wondering how I could make a certain number of variables with a different name in a more efficient way. For now I'm doing something like this:
for(int i=1; i<=x; i++)
switch(i) {
case 1:
Player player1=new Player(i, x);
break;
case 2:
Player player2=new Player(i, x);
break;
case 3:
Player player3=new Player(i, x);
break;
case 4:
Player player4=new Player(i, x);
break;
case 5:
Player player5=new Player(i, x);
break;
case 6:
Player player6=new Player(i, x);
break;
}
I'm just wondering whether there are more effecient ways to solve this and what those ways are.
You'd be better off making an array:
var players = new Player[x];
for (int i = 0; i < x; i++)
{
players[i] = new Player(i, x);
}
or use Linq:
var players = Enumerable.Range(0, x)
.Select(i => new Player(i, x))
.ToArray();
You can then reference the players you created with.
var player1 = players[0]; // Note: array indexes start at 0
Of course, you may not actually need to use arrays, specifically. Many other collection classes might suit your problem better.
Further reading:
Arrays (C# Programming Guide)
Collections (C# and Visual Basic)
You could make a List of players
var players = new List<Player>;
for (int i = 0; i < x; i++)
{
players.add(new Player(i, x));
}
Then the memory would be distributed at runtime.
I prefer not to use array's because you have to know in advance what size they will be. With lists you can dynamically assign value's and It will only ever take up as much space in memory as the list is in its current state.
I don't program in C# but it seems you're creating local variables : they are valid only in your loop.
Name your variables outside of the loop, then create them inside of it. You will have to test if they exist to work with them.
Just for a trick:
partial class Player {
public Player(int i, int x) {
this.Ordinal=i;
}
public int Ordinal {
get;
set;
}
public static int Total {
get;
set;
}
public delegate Trick Trick(out Player x);
public static Trick Create(out Player x) {
x=new Player(++Player.Total, 0); // the second int doesn't matter
return Create;
}
}
partial class TestClass {
public static void TestMethod() {
Player mom, dad, brother, sister, me;
Player.Create(out mom)(out dad)(out brother)(out sister)(out me);
}
}
You might want to define another way to implement the Total once you have more than one series of Player.
Related
I'm sorry if there is a similar question, tried searching but didn't find an adequate response for my use.
I have 5 classes that herits from one class (spaceshipclass) and I need to create random objects from each class and store them in a binary tree.
with each one of the objects, two random integers as shown in the code bellow.
public class spaceships
{
int cost;
int combatPower;
private Random rand = new Random();
public spaceships(int cost, int combatPower)
{
this.cost = cost;
this.combatPower = combatPower;
cost = rand.Next(10000, 1000000);
combatPower = rand.Next(20, 100);
}
}
public class Patrol : spaceships
{
public Patrol (int cost,int combatPower) : base(cost,combatPower)
{
}
}
the second class is one of the inherited classes.
I hope someone can help me.
There seems to be a disconnect between the desired functionality and the posted code, as your spaceships class takes in a cost and combatPower in its constructor, but then ignores that and calculates those values itself. Because of this, I'm going to ignore that particular implementation and just go ahead and calculate those values before constructing the random objects, as your question title requests. Keep in mind that my solution allows you to remove the private Random rand field of your spaceships class entirely.
You could use a simple switch statement to determine which type of spaceships to create, and then add them to your collection (you mention a binary search tree but that's an implementation detail that doesn't really matter here, so long as it is of type spaceships to support the polymorphism your question mentions).
Random rand = new Random();
for (int i = 0; i < numSpaceshipsRequired; i++)
{
int typeOfSpaceship = rand.Next(0, 5);
int cost = rand.Next(10000, 1000000);
int combatPower = rand.Next(20, 100);
switch (typeOfSpaceship)
{
case 0:
collection.Add(new Patrol(cost, combatPower));
break;
case 1:
collection.Add(new Cruiser(cost, combatPower));
break;
case 2:
collection.Add(new Frigate(cost, combatPower));
break;
case 3:
collection.Add(new Fighter(cost, combatPower));
break;
case 4:
collection.Add(new Stealth(cost, combatPower));
break;
}
}
I need some help with the way I am storing objects/data inside my application. I am creating an application that: creates a robot, assigns tasks to robot, displays the robot information with task time etc..
I have setup multiple different objects to be instantiated in Main when the program is run. Then the user will select a robot type from the list of types. I am having trouble passing the botType object into the Robot object. I am asking the user to select a botType 1-6 using int, then I would like the user selected int to define which botType should be applied to the Robot.
Because I am initializing the BotTypes in Main, then using a different method to CreateRobot(). I am having trouble passing the botType into the Robot object. I can pass the integer the user selects but this is not passing the botType into Robot like I am trying to complete..
Here are my classes/constructors being used:
public class Robot
{
//Store robot name
public string botName { get; set; }
//Store robot type
public BotType botType { get; set; }
//Store time to complete task
public int timeElapsed { get; set; }
public Robot(string BotName, BotType botType, int TimeElapsed)
{
this.botName = BotName;
this.botType = new BotType();
timeElapsed = TimeElapsed;
}
public class BotType
{
//Type of robot
public string TypeName { get; set; }
//Type of task represented by number
public int TaskType { get; set; }
//contructor to set values
public BotType (string typeName, int taskType)
{
TypeName = typeName;
TaskType = taskType;
}
Then my main method where the objects are being initialized but when I try to use them, I am unable to convert user defined int into BotType like I would like..
public class BotOMat
{
public static List<Robot> botList = new List<Robot>();
public static List<BotTask> botTaskMap = new List<BotTask>();
public static List<BotType> botTypeMap = new List<BotType>();
static void Main(string[] args)
{
//initalize bot types
BotType UNIPEDAL = new BotType("Unipedal", 1);
BotType BIPEDAL = new BotType("Bipedal", 2);
BotType QUADRUPEDAL = new BotType("Quadrupedal", 3);
BotType ARACHNID = new BotType("Arachnid", 4);
BotType RADIAL = new BotType("Radial", 5);
BotType AERONAUTICAL = new BotType("Aeronautical", 6);
//initialize bot tasks
BotTask DISHES = new BotTask("Do the dishes", 1000, 0);
BotTask SWEEP = new BotTask("Sweep the house", 3000, 0);
BotTask LAUNDRY = new BotTask("Do the laundry", 10000, 0);
BotTask RECYCLING = new BotTask("Take out the recycling", 4000, 0);
BotTask SAMMICH = new BotTask("Make a sammich", 7000, 0);
BotTask LAWN = new BotTask("Mow the lawn", 20000, 0);
BotTask RAKE = new BotTask("Rake the leaves", 18000, 0);
BotTask BATH = new BotTask("Give the dog a bath", 14500, 0);
BotTask BAKE = new BotTask("Bake some cookies", 8000, 0);
BotTask WASH = new BotTask("Wash the car", 20000, 0);
var botTaskMap = new List<BotTask> { DISHES, SWEEP, LAUNDRY, RECYCLING, SAMMICH, LAWN, RAKE, BATH, BAKE, WASH };
var botTypeMap = new List<BotType> { UNIPEDAL, BIPEDAL, QUADRUPEDAL, ARACHNID, RADIAL, AERONAUTICAL };
private static void createRobot()
{
//Get robot name, add to list saving multiple names.
Console.WriteLine("Enter robot name:");
string botName = Console.ReadLine();
//Get robot type
Console.WriteLine("Enter robot type: (number)");
int botType = Convert.ToInt32(Console.ReadLine());
//botType = botTypeMap[botType];
//boxing to convert int to BotType
//error handling
if (botType < 1 || botType > 6)
{
Console.WriteLine("Invalid input. Please enter number 1-6.");
//BotType.TaskType = 0;
}
//Add robot to the class storing robot information.
if (botType > 1 || botType < 6)
{
Robot aRobot = new Robot(botName, botType, 0);
botList.Add(aRobot);
aRobot.AssignBotTask();
aRobot.CompleteTask();
}
else
{
MainMenu();
}
}
I can either pass BotType into Robot as an Integer or receive an Arguement 2: cannot convert from int to BotOMat.BotType. Whenever I try to write any output using aRobot the console is writing using the protected variables which is not the desired output.
Should I be creating aRobot in the Robot class? I then need to assign BotTask(s) to the robot later on... I believe these use an Association type relationship but if the objects are not initialized in each class. I am unsure how to initiate; for example: a Unipedal Robot that does the Dishes.
I appreciate any help in advance. I tried to be as descriptive as possible without posting a repeat question as any other example I can find is much more basic than what I believe I am trying to accomplish here.
The next time you post a question, you should take a look at the help, particularly in regards to preparing a Minimally Reproduceable Example. Your code doesn't compile, you are missing types, functions, etc. Some of what I'm going to show below doesn't quite comport to what you show, but it certainly seems to meet your intention (at least to me).
I'm going to start at the bottom layer and work up. Your BotType class simply has a string and an int (with the ints incrementing). Instead of using a class, I'm going to use an enum (you should read up on these). Enums are value types. Under the covers, they end up being represented by a simple integral-valued type (like int), but with the metadata they include, they have a symbolic name as well. So:
public enum RobotType
{
Unipedal = 1,
Bipedal,
Quadrupedal,
Arachnid,
Radial,
Aeronautical,
}
Had I not included the =1, then Unipedal would have started with the default value (zero). You'll see why starting at one makes sense below. The nice thing about enums is that you can convert them to an integer, or to a string that represents their symbol. You can also parse either a string containing an integer or a string containing symbolic name to an enum instance:
var asInt = (int) RobotType.Unipedal;
var asString = RobotType.Unipedal.ToString();
bool isGoodParse = Enum.TryParse<RobotType>("1", out RobotType parsedFromInt);
isGoodParse = Enum.TryParse<RobotType>("Unipedal", out RobotType parsedFromString);
All that code works the way you might expect.
It's tempting to just do the same thing with your task types. But the names aren't valid C# symbols (they have spaces). Instead, we'll use System.ComponentModel.DescriptionAttribute to add some extra metadata to the enum values:
public enum RobotTaskName
{
[Description("Do the dishes")]
DoTheDishes = 1,
[Description("Sweep the house")]
SweepTheHouse,
[Description("Do the laundry")]
DoTheLaundry,
[Description("Take out the recycling")]
TakeOutTheRecycling,
[Description("Make a sammich")]
MakeASammich,
[Description("Mow the lawn")]
MowTheLawn,
[Description("Rake the leaves")]
RakeTheLeaves,
[Description("Give the dog a bath")]
GiveTheDogABath,
[Description("Bake some cookies")]
BakeSomeCookies,
[Description("Wash the car")]
WashTheCar,
}
But, now we can't just call ToString on the enum value to get the corresponding name. Instead, we'll use reflection to dig the name out of the Description attribute:
public static class RobotExtensions
{
public static string GetDescription<T>(this T enumValue) where T : struct, Enum
{
var enumInfo = typeof(T).GetField(enumValue.ToString());
if (enumInfo != null)
{
var attributes = enumInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
return ((DescriptionAttribute[])attributes)[0].Description;
}
}
//otherwise
return enumValue.ToString();
}
}
That code declares an Extension Method for enums (you can call it directly on an enum - any enum). It gets reflected Field Information for the enum value, checks to see if it has an DescriptionAttribute. If it does, it digs out the description and returns it. If it can't get that information, it simply returns enumValue.ToString. As a result:
RobotTaskName.DoTheDishes.GetDescription(); //returns "Do the dishes"
RobotType.Arachnid.GetDescription(); //returns "Arachnid"
The other cool thing about doing it this way, is that we can write some code that prompts the user for a particular enum value, checks it's validity, etc:
public static T? GetResponseUsingEnum<T>(string prompt) where T : struct, Enum
{
//Loop until a good answer (or no answer)
while (true)
{
Console.WriteLine($"{prompt}: Please enter one of:");
var values = (T[])Enum.GetValues(typeof(T));
foreach (var enumValue in values)
{
var description = enumValue.GetDescription<T>();
var intValue = Convert.ToInt32(enumValue);
Console.WriteLine($"{intValue}: {description}");
}
Console.Write(">> ");
var response = Console.ReadLine();
if (string.IsNullOrEmpty(response))
{
return (T?)null;
}
if (Enum.TryParse<T>(response, out var val))
{
if (values.Contains(val))
{
Console.WriteLine($"You answered: {val}");
return val;
}
}
}
}
That code shows the integer and string representations of all of the values of a particular enumerated type, and then prompts the user to enter a value. If the user enters a value out of range, then it re-prompts him/her. If the user just hits Enter, then it returns a null value. Otherwise, if the user enters a valid answer, it returns the answer (not as an integer, but as a properly typed enumerated item.
Now that the bottom layer is complete, let's work up ...
I couldn't quite tell what your Robot Task type does, or what the extra two integers where, so I called them Num1 and Num2. I also added a Perform function that "performs" the task (echoes it to the console).
public class BotTask
{
public RobotTaskName Name { get; set; }
public string Description => Name.GetDescription();
public int Num1 { get; set; }
public int Num2 { get; set; }
public BotTask(RobotTaskName name, int num1, int num2)
{
Name = name;
Num1 = num1;
Num2 = num2;
}
public void Perform()
{
Console.WriteLine($" - Peforming Task: {Name.GetDescription()} with {Num1} and {Num2}");
}
}
If you are curious, the Description property is a read-only property that calls GetDescription on the underlying RobotTaskName enumerated type.
Then I recreated your Robot type. I don't know what your intention was for the TimeElapsed property. But, I changed it to a TimeSpan from an int - because, well, that's what TimeSpans are for.
public class Robot
{
public string BotName { get; set; }
public RobotType BotType { get; set; }
public string BotTypeDescription => BotType.GetDescription();
public TimeSpan TimeElapsed { get; set; }
private List<BotTask> _tasks = new List<BotTask>();
public IEnumerable<BotTask> Tasks => _tasks;
public Robot(string botName, RobotType botType, TimeSpan timeElapsed = default)
{
this.BotName = botName;
this.BotType = botType;
TimeElapsed = timeElapsed;
}
public void AddTask (BotTask task)
{
_tasks.Add(task);
}
public void Show()
{
Console.WriteLine($"Robot: {BotName}, Type: {BotTypeDescription}, TimeElapsed: {TimeElapsed}");
foreach (var task in Tasks)
{
task.Perform();
}
}
}
Note that I also added a list of tasks that have been assigned to each robot. That includes the list, an AddTask method to add tasks to a robot, etc.
Finally, I added a Run method to the Robot class that fires the whole thing off (call it from Main). It allows you to create more than one robot and to assign more than one task to each robot. It uses the GetResponseUsingEnum method to get both the robot type and the task type. This means a consistent user interface and some healthy code reuse (if you find a bug in that function, you fix two pieces of functionality).
public static void Run()
{
var robotsList = new List<Robot>();
//loop until there are no more robots
while (true)
{
Console.Write("Enter robot name: ");)
var robotName = Console.ReadLine();
if (string.IsNullOrEmpty(robotName))
{
break; //empty robot, time to list things out
}
RobotType? robotType = null;
while (!robotType.HasValue)
{
robotType = GetResponseUsingEnum<RobotType>("Robots");
}
var robot = new Robot(robotName, robotType.Value);
robotsList.Add(robot);
Console.WriteLine("Time to add some tasks for this robot");
//get tasks - loop until no more tasks
while (true)
{
var taskName = GetResponseUsingEnum<RobotTaskName>("RobotTaskName");
if (!taskName.HasValue)
{
break; //no more tasks
}
var task = new BotTask(taskName.Value, 100, 200);
robot.AddTask(task);
}
}
//At this point, we have a fully populated list of robots, each with some tasks
foreach (var robot in robotsList)
{
robot.Show();
}
}
Finally, if you run it, the output looks like this:
Enter robot name: Robby
Robots: Please enter one of:
1: Unipedal
2: Bipedal
3: Quadrupedal
4: Arachnid
5: Radial
6: Aeronautical
>> 2
You answered: Bipedal
Time to add some tasks for this robot
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 2
You answered: SweepTheHouse
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 3
You answered: DoTheLaundry
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>>
Enter robot name: SecondRobot
Robots: Please enter one of:
1: Unipedal
2: Bipedal
3: Quadrupedal
4: Arachnid
5: Radial
6: Aeronautical
>> 3
You answered: Quadrupedal
Time to add some tasks for this robot
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 8
You answered: GiveTheDogABath
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>> 10
You answered: WashTheCar
RobotTaskName: Please enter one of:
1: Do the dishes
2: Sweep the house
3: Do the laundry
4: Take out the recycling
5: Make a sammich
6: Mow the lawn
7: Rake the leaves
8: Give the dog a bath
9: Bake some cookies
10: Wash the car
>>
Enter robot name:
Robot: Robby, Type: Bipedal, TimeElapsed: 00:00:00
- Peforming Task: Sweep the house with 100 and 200
- Peforming Task: Do the laundry with 100 and 200
Robot: SecondRobot, Type: Quadrupedal, TimeElapsed: 00:00:00
- Peforming Task: Give the dog a bath with 100 and 200
- Peforming Task: Wash the car with 100 and 200
The scenario is that I have say two different types of cases - case 1 and case 2. For case 1 and case 2 each I have a certain startIndex, endIndex and a formula for accessing the elements of a List.
Now for assigning values startIndex and endIndex I am preferring a normal switch case, however I am at loss for the formula for accessing elements. For case 1 it is say something like List[ a+i ] and for case 2 it is say List[a + (i-b)].
One way can be to have a for loop like this
for(int i=0;;i++)
{
if(case is 1)
then f=a+i
else if(case 2)
then f=a+(i-b)
}
I thought of using delegates. however, as per my knowledge they need to be made global. Actions do not return value. Func can be used but one expression/formula takes only one element (int) and the other takes 3. I need something in lines to this like that anonymous function can be assigned any of above mentioned formulae at runtime from the switch case (as the cases might and will increase in future).
Thank you.
I thought of using delegates. however, as per my knowledge they need
to be made global.
This is not true (actually, there are no truly global variables in C#, since each and every variable needs to be encapsulated inside an object). A public delegate type is indeed visible to all code after referencing the assembly containing this type's code, but a variable of such type can be private.
What I recommend in your situation is to have some sort of mapping from case numbers to delegates. A good idea is to use a Dictionary<TKey, TValue> if you have at most one delegate per case. This dictionary can be stored as a private variable inside the class where your method resides.
public class MyClass
{
private Dictionary<int, Delegate> _delegateMapping = new Dictionary<int, Delegate>;
}
There are a couple of ways you can add elements do the dictionary in the constructor: passing the already populated dictionary, passing an array of delegates, creating these delegates in the constructor itself. Either way, you'll end up with a dictionary of Delegate types, so you'll need to use a cast to be able to use them in your code properly.
for (int i = 1; i < _delegateMapping.Count; i++)
{
switch (i)
{
case 1:
var f = (Action<int>)_delegateMapping[1];
f(i);
break;
case 2:
var f = (Action<int, int>)_delegateMapping[2];
f(i, a);
break;
}
}
Of course I'm greatly improvising here.
It is important to note that if the type of delegate changes inside the dictionary, you will have to modify the cast accordingly inside the switch statement. Otherwise, if no implicit cast exists, you'll get a runtime exception.
Hi guys thank you so very much for your feedbacks. I finally found the solution with Func. This is what my code looks like. I had to manipulate the Func usage a little. I made almost all the vars which I have to use in the Func as global/local to the function where I write these Funcs. My apologies, if I was not able to explain my problem properly.
int i = -1;
Func<int,int> formula = null;
switch(f)
{
case 1:
{
formula = new Func<int,int>(index => { return i; });
}
break;
case 2:
{
formula = new Func<int, int>( index => { return s- (i * c); } );//here s and c are global variables.
}
break;
}
i = startIndex;
while(i < endIndex)
{
var Obj= List[formula.Invoke(i)];
//my code goes here
i++;
}
Let me know if my solution is correct w.r.t performance, logic, C# programming, etc.. :)
EDITED::
#usr and #Kapol I tried the way you suggested and tried to improvise the code like this.
private Dictionary<int, Func<int[], int>> indexFormulae;
private void assignDelegates()
{
indexFormulae = new Dictionary<int, Func<int[], int>>();
indexFormulae.Add(0, getFormula_1);
indexFormulae.Add(1, getFormula_2);
}
private void someFunction(int sp)
{
int i = 0;
Func<int[], int> formula = null;
indexFormulae.TryGetValue(formation,out formula);
i = startIndex;
while (i < endIndex)
{
int[] intValues = new int[] {i,sp,globalVar };
var Obj = List[formula.Invoke(intValues)];
//My code here
i++;
}
}
private int getFormula_1(params int[] intValues)
{
return intValues[0];
}
private int getIndex_Vertical(params int[] intValues)
{
return intValues[1] - (intValues[0] * intValues[2]);
}
So, that with this now I can use these two getFormula methods anywhere in this class rather than keeping them anonymous. and also I think I will stick to params because I might have N number of int params in future for other functions.
I am looping through a list and would like to add multiple occurrences, should I find them.
so far I have,
public struct optionsSort
{
public string name;
public string date;
public double strike;
public string callPut;
public double size;
public string isin;
}
List<List<optionsSort>> stocks = new List<List<optionsSort>>();
optionsSort tempStock1 = new optionsSort();
List<optionsSort> posCheckOptions = new List<optionsSort>();
then some code, then,
for(int k = 0; k<posCheckOptions.Count; k++)
{
for(int l = 0; l<posCheckOptions[l].Count; l++)
{
if(posCheckOptions[l+1] == null)
{
//finished the iteration
break;
}
else if
(posCheckOptions[k][l + 1].date == posCheckOptions[k][l].date
&& posCheckOptions[k][l + 1].strike == posCheckOptions[k][l].strike
&& posCheckOptions[k][l + 1].callPut == posCheckOptions[k][l].callPut)
{
posCheckOptions[k][l].size = posCheckOptions[k][l].size
+ posCheckOptions[k][l + 1].size;
}
}
}
Basicly, Im looking forward from the start of the list. asking the question, are certain elements of the list at i+1 the same as i, if so, add those elements to i and delete the entire row.
i get this error
"Error 1 Cannot modify the return value of 'System.Collections.Generic.List.this[int]' because it is not a variable C:\Users\WindowsFormsApplication1\WindowsFormsApplication1\ReadCSV.cs 890 25 WindowsFormsApplication1
"
Many Thanks for looking.
I believe your problem is that you are using a mutable struct. Mutable structs are evil.
The simplest solution is to change optionsSort to a class. That should fix the error message.
To explain the error message, when you call posCheckOptions[k][l], since optionsSort is a struct, it returns a copy of the value in the list. When you change size, it will update the copy, but not the one in the list. The copy would then be discarded. The compiler recognizes this and stops you.
I recommend you read up on the differences between reference types and value types.
I have recently moved to .net 3.0 (windows forms, C#). I want to know more about predicates and lambda expressions. Where should we use them? Do they improve performance? and how do they work internally. Thanks.
If you search Stack Overflow you'll find about a thousand answers explaining what they're for. In short - a lambda is a way of writing an anonymous method at the point where you want to pass it to another method. Technically the same as the delegate syntax for an anonymous method, although with added powers of type inference so you don't need to state the parameter types. A predicate is a method that accepts some value and returns a bool - an example would be the argument to Where.
A lambda that doesn't refer to any external variables gets turned into a private static method with a made-up name. If it refers to instance members of the enclosing class, it becomes an instance method. If it refers to local variables, those variables get "hoisted" into being fields of a compiler-generated class that is allocated when the enclosing method starts running, and the lambda's body becomes a method in that new class.
As for performance, they don't make that much difference. They involve the creation of temporary objects, but I find that these are collected extremely efficiently by the GC.
If you want to study the different versions of C# and how they different .My suggestion is read the book C.Sharp.in.Depth by jon skeet . This will give you the better understanding of new versions
Do they improve performance? and how
do they work internally. Thanks.
For the most part, you'll never notice the performance hit. However, there are some pathological cases which will kill performance, namely overzealous use of fixed point combinators.
Its a well-known trick that we can use the Y-combinator to write recursive lambda functions, however consider the following code:
using System;
using System.Diagnostics;
namespace YCombinator
{
class Program
{
static Func<T, U> y<T, U>(Func<Func<T, U>, Func<T, U>> f)
{
return f(x => y<T, U>(f)(x));
}
static int fibIter(int n)
{
int fib0 = 0, fib1 = 1;
for (int i = 1; i <= n; i++)
{
int tmp = fib0;
fib0 = fib1;
fib1 = tmp + fib1;
}
return fib0;
}
static Func<int, int> fibCombinator()
{
return y<int, int>(f => n =>
{
switch (n)
{
case 0: return 0;
case 1: return 1;
default: return f(n - 1) + f(n - 2);
}
});
}
static int fibRecursive(int n)
{
switch (n)
{
case 0: return 0;
case 1: return 1;
default: return fibRecursive(n - 1) + fibRecursive(n - 2);
}
}
static void Benchmark(string msg, int iterations, Func<int, int> f)
{
int[] testCases = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20 };
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i <= iterations; i++)
{
foreach (int n in testCases)
{
f(n);
}
}
watch.Stop();
Console.WriteLine("{0}: {1}", msg, watch.Elapsed.TotalMilliseconds);
}
static void Main(string[] args)
{
int iterations = 10000;
Benchmark("fibIter", iterations, fibIter);
Benchmark("fibCombinator", iterations, fibCombinator());
Benchmark("fibRecursive", iterations, fibRecursive);
Console.ReadKey(true);
}
}
}
This program prints out:
fibIter: 14.8074
fibCombinator: 61775.1485
fibRecursive: 2591.2444
fibCombinator and fibRecursive are functionally equivalent and have the same computational complexity, but fibCombinator is a full 4100x slower due to all of the intermediate object allocations.