Am I doing it right C# regarding parsing using delegate? - c#

I want to parse string into version numbers using delegate. The delegate requires a string as an argument and produces integer array as an output.
There are two errors
Error CS0136 A local or parameter named 'arrayString' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
Error CS0029 Cannot implicitly convert type 'System.Collections.Generic.List<int>' to 'int'
namespace TEST
{
class Program
{
public delegate int Parsing(string parsee);
static void Main(string[] args)
{
Parsing parsee = new Parsing(Parse);
Console.WriteLine();
}
public static int Parse(string arrayString)
{
Console.WriteLine("Write the version numbers : ");
var input = Console.ReadLine();
string[] arrayString = input.Split('-');
List<int> listInt = new List<int>();
foreach (string i in arrayString)
{
listInt.Add(Convert.ToInt32(i));
}
listInt.ToArray();
foreach (var item in listInt)
{
Console.WriteLine(item);
}
return listInt;
}
}
}
I am a noob.

The identifier "arrayString" is defined twice.
Local variables as well as arguments are not allowed to be defined with the same name, otherwise accessing the identifier would have ambiguous meaning.
As long as the Parse method is named "parse", it should act as-is. It takes an argument as input and outputs the produced result, which is the only duty of it. while Console.ReadLine or Console.WriteLine are not a part of "Parse" but "Input".
You need more learning on the basic syntax and the built-in types before you start learning delegate.
The solution that maybe matches your requirement as a demo is:
namespace Test
{
internal static class Program
{
internal static void Main(string[] args)
{
Console.WriteLine("Write the version numbers : ");
var input = Console.ReadLine();
var results = ParseInts(input.Split('-'), ParseInt);
foreach (var item in results)
{
Console.WriteLine(item);
}
}
private static IEnumerable<int> ParseInts(IEnumerable<string> values, Func<string, int> parser)
{
foreach (var item in values)
{
yield return parser(item);
}
}
private static int ParseInt(string value)
=> Convert.ToInt32(value);
}
}
But simply we use this to get int values:
var input = Console.ReadLine();
var results = input.Split('-').Select(int.Parse);
instead of writing everything.

Related

CSharpScript.EvaluateAsync The name x doesnt exsist in the current context [duplicate]

I am working on a C# application, and I would like the ability to execute code from a string, where that string contains a variable in scope outside the string. For example:
using Microsoft.CodeAnalysis.CSharp.Scripting;
///...
List<int> myNumbers = new List<int>();
//do something here to populate myNumbers
//userProvidedExpression will be a string that contains curNumber and represents a statement that would evaluate to a bool
string userProvidedExpression = "curNumber == 4";
foreach(int curNumber in myNumbers)
{
if( await CSharpScript.EvaluateAsync<bool>(userProvidedExpression) )
{
Console.WriteLine("curNumber MATCHES user-provided condition");
}
else
{
Console.WriteLine("curNumber DOES NOT MATCH user-provided condition");
}
}
Obviously the key difficulty I am having is getting the "curNumber" from userProvidedExpression to be recognized as the same curNumber from the foreach loop. Is there any straightforward way to accomplish this?
As the documentation says, you need to add a globals, like that:
public class Globals
{
public int curNumber;
}
async static void Main(string[] args)
{
List<int> myNumbers = new List<int>();
myNumbers.Add(4);
//userProvidedExpression will be a string that contains curNumber and represents a statement that would evaluate to a bool
string userProvidedExpression = "curNumber == 4";
foreach (int curNumber in myNumbers)
{
var globals = new Globals
{
curNumber = curNumber
};
if (await CSharpScript.EvaluateAsync<bool>(userProvidedExpression, globals: globals))
{
Console.WriteLine("curNumber MATCHES user-provided condition");
}
else
{
Console.WriteLine("curNumber DOES NOT MATCH user-provided condition");
}
}
Console.ReadLine();
}

How to get parameter name with C#

How can we get parameter name called by a method in C#?
Example:
public static void PrintList (List<string> list)
{
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
PrintList(oxygenList);
I need the method to print:
oxygenList
Thanks.
If you're using C# 10 or later, you can use the new CallerArgumentExpression attribute to achieve this:
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public static class Program
{
public static void Main()
{
List<string> oxygenList = new List<string> { "A", "B", "C" };
PrintList(oxygenList);
}
public static void PrintList(List<string> list, [CallerArgumentExpression("list")] string? name = null)
{
Console.WriteLine("Argument name = " + name); // Prints "Argument name = oxygenList
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
}
However, note that this gives the expression used when calling the method - so if you call it with this code:
public static void Main()
{
PrintList(getOxygenList());
}
public static List<string> getOxygenList()
{
return new List<string> { "A", "B", "C" };
}
the value passed as name will be "getOxygenList()".
It has to work like this because an expression can be used for the parameter - it's not restricted to a simple variable name.
You should use:
Console.WriteLine(nameof(list));
See more: nameof
Update:
This is still not clear for me what do You want to achieve but the easiest way would be:
public static void PrintList (List<string> list, string nameOfList)
{
Console.WriteLine(nameOfList);
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
PrintList(oxygenList, nameof(oxygenList));
You may also create a bit cleaner extension method, like this:
public static class ListPrinter
{
public static void PrintListWithName(this List<string> list, string nameOfList)
{
Console.WriteLine(nameOfList);
list.ForEach(element => Console.WriteLine(element));
}
}
called like this:
oxygenList.PrintListWithName(nameof(oxygenList));

Convert object to IEnumerable of anonymous type

How do I iterate over the anonymous type that is passed in as an object below (first, second, third) => new { One = first, Two = second, Three = third }
If I interrogate the type of message and print it, it says:<>f__AnonymousType0 3[MtApi.MtQuote,MtApi.MtQuote,MtApi.MtQuote]
//**How do I convert an object to the anonymous type?**
static void ShowAnonymousTypeMessage(object message)
{
foreach(var quote in message)
Console.WriteLine(
quote.Instrument + ": " + quote.Bid.ToString() + quote.Ask.ToString());
}
...
var pattern = observable1.And(observable2).And(observable3);
var plan = pattern.Then((first, second, third) => new { One = first, Two = second, Three = third });
var zippedSequence = Observable.When(plan);
zippedSequence.Subscribe(
ShowAnonymousTypeMessage
);
This is working for me:
static void Main()
{
var anon = new { Name = "Terry", Age = 34 };
test(anon);
}
static void test(dynamic t)
{
Console.WriteLine(t.Age);
Console.WriteLine(t.Name);
}
Anonymous types aren't intended to be passed around and you should only use object when absolutely necessary. Also you can't iterate over an anonymous type - you should use an Array.
var pattern = observable1.And(observable2).And(observable3);
var plan = pattern.Then((first, second, third) => new[] { first, second, third });
var zippedSequence = Observable.When(plan);
zippedSequence.Subscribe(
ShowAnonymousTypeMessage
);
Anonymous types aren't meant to be passed around, for the same reason we have strong typing in C# at all: The compiler doesn't make careless errors or forget things, and we often do. If your anonymous class instances are leaving the scope where they were created, it's time for them to grow up and be a real class.
Usually I'd say you should write a quickie class with appropriate properties (guessing at the property types here):
public class Thing {
public String One { get; set; }
public String Two { get; set; }
public String Three { get; set; }
}
But a Tuple<T1,T2,T3> is just as good really, if you've got property names like One, Two, and Three anyway:
public static void Main()
{
var x = Enumerable.Range(0, 10).Select(n => new Tuple<int, string>(n, $"Item {n + 1}"));
Test(x);
}
private static void Test(IEnumerable<Tuple<int, string>> stuff)
{
foreach (var item in stuff)
{
Console.Write($"{item.Item1}: {item.Item2}");
}
}
dynamic works, but dynamic is like the Vise-Grip: "Always the Wrong Tool for Every Job, Since 1921". dynamic has a legitimate but small role in the typesystem. It's not there so we can turn the whole language into JavaScript.
public static Main()
{
var x = Enumerable.Range(0, 10).Select(n => new { ID = n, Value = $"Item {n + 1}" });
Test(x);
}
private static void Test(dynamic message)
{
foreach (dynamic item in message)
{
Console.Write($"{item.ID}: {item.Value}");
}
}
OK, the Vise-Grip isn't always the wrong tool either. But it's rare there isn't a better one.

I want to sort the string array. I know to achieve the result in diff ways. But I want to know why this method is throwing an error

I'm getting an
Object reference not set
exception in this Program..
Where I store Output1[k++] there is a problem...
CODE:
Class stringsor
{
public static string[] output1;
public static void sortstrings(string[] input1)
{
int k = 0;
foreach (var item in input1)
{
output1[k++] = (item.OrderBy(i => i)).ToString();
}
Sorting Using Linq
output1 = new string[k];
foreach(var item in output1)
{
Console.WriteLine(item);
}
}
public static void Main(string[] args)
{
string[] input1 = { "Adkad","jor","ioeuo","zkas","aka","nma"};
sortstrings(input1);
}
}
You have declared output1, but not initialized it.
Before you use it in sortStrings, try.
output1 = new string[input1.Length];
problem is you are not initializing output array before using it. Since you already using LINQ you can initialize and assign output array directly like below
public static void sortstrings(string[] input1)
{
output1 = input1.Select(word => new string(word.OrderBy(i => i).ToArray())).ToArray();
foreach (var item in output1)
{
Console.WriteLine(item);
}
}
I want to sort the string array.
But what you currently doing is reversing the order of characters in the output array. it is not sort the string array. is that what you expect? if you need to order the strings you can so as below
output1 = input1.OrderBy(word => word).ToArray();

Issue with extension method

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace LambdaExtensionEx
{
class Program
{
static void Main(string[] args)
{
string[] myStrngs = new string[] { "Super","Simple","Okay"};
IEnumerable<string> criteraStrngs = myStrngs.WhereSearch<string>(delegate(string s)
{
return s.StartsWith("s");
});
string s1 = "dotnet";
int count = s1.GetCount();
Console.ReadLine();
}
}
public static class MyExtension
{
public delegate bool Criteria<T>(T Value);
public static IEnumerable<T> WhereSearch<T>(this IEnumerable<T> values, Criteria<T> critera)
{
foreach (T value in values)
if (critera(value))
yield return value;
}
public static int GetCount(this string value)
{
return value.Count();
}
}
}
I am able to call GetCount extension method and I get result in 'count'. But WhereSearch is not being called in any time and not getting result. What mistake am I doing?
You need to start enumerating over the result returned by the WhereSearch function if you want it to get executed. The reason for that is because this function yield returns an IEnumerable<T>. What the C# compiler does is build a state machine and doesn't execute the function immediately until the calling code starts enumerating over the result.
For example:
// The function is not executed at this stage because this function uses
// yield return to build an IEnumerable<T>
IEnumerable<string> criteraStrngs = myStrngs.WhereSearch<string>(delegate(string s)
{
return s.StartsWith("s");
});
// Here we start enumerating over the result => the code will start executing
// the function.
foreach (var item in criteraStrngs)
{
Console.WriteLine(item);
}
Another example is calling some of the LINQ extension methods such as .ToList() on the result which will actually enumerate and call the function:
IEnumerable<string> criteraStrngs = myStrngs.WhereSearch<string>(delegate(string s)
{
return s.StartsWith("s");
})
.ToList();
For more details on how lazy loading works in this case you may take a look at the following post.
Your extension methods class doesn't make much sense - why don't you just do this?
class Program
{
static void Main(string[] args)
{
string[] myStrngs = new string[] { "Super", "Simple", "Okay" };
IEnumerable<string> criteraStrngs = myStrngs.Where(x => x.StartsWith("s"));
string s1 = "dotnet";
int count = s1.Count();
Console.ReadLine();
}
}
As stated by Darin Dimitrov previously - you will still need to enumerate criteriaStrngs to get a result out of it - which is what was wrong with your original code.
HTH

Categories