I have this on a button:
private void Button_Click(object sender, RoutedEventArgs e)
{
string s = "x12y04";
//make new instance for MyMath class
MyMath dRet01 = new MyMath();
//use the doubleArrayXY (in MyMath class) to get doubble array back
double[] retD = dRet01.doubleArrayXY(s);
//use the calcResultFromDoubleArray (in MyMath class) to get result
MyMath dRet02 = new MyMath();
double result = dRet02.calcResultFromDoubleArray(retD[0], retD[1]);
//DEBUG!
/*
string TEST1 = Convert.ToString(returnedDouble[0]);
MessageBox.Show(TEST1);
string TEST2 = Convert.ToString(returnedDouble[1]);
MessageBox.Show(TEST2);
string TEST3 = Convert.ToString(result);
MessageBox.Show(TEST3);
*/
}
where the class "MyMath" is:
public double[] doubleArrayXY(string inputValue)
{
//in case there are upper case letters, set all to lower
string inpLow = inputValue.ToLower();
//split the string on the Y (so this tech should also work for x89232y329)
//so this will create res[0] that is x89232 and an res[1] that is 329
string[] res = inpLow.Split(new string[] { "y" }, StringSplitOptions.None);
//in the first string that looks like x89232, remove the x
string resx = res[0].Replace("x", null);
//now get the x value to a double
double x = double.Parse(resx);
//now get the y valye to a double
double y = double.Parse(res[1]);
//return in a double array the x and then the y (x=double[0] and y=double[1])
return new double[] {x,y};
}
public double calcResultFromDoubleArray(double one, double two)
{
return (one * two);
}
Now I know the part in the class that is "calcResultFromDoubleArray" is kind of useless at this point, but I want to make that do some extra stuff later on.
what I wonder about the most is in the main code where I make this new dRet10, and later on make dRet02.
I was thinking at first I could do something like this:
double result = dRet01.calcResultFromDoubleArray(retD[0], retD[1]);
So in that case I would not need to create a new instance of MyMath, but this does not work.
So I need to call a new instance for the class (like I did), or can I do this in a more elegant way?
I'm still kind of new to C#, so I'm trying to learn how to program in a nice and elegant way, besides just making it work.
Since your methods don't really use any other state information besides the parameters passed they probably should be static so you would not have to create any instances of your class at all:
double[] retD = MyMath.DoubleArrayXY(s);
double result = MyMath.CalcResultFromDoubleArray(retD[0], retD[1]);
If all of your methods in MyMath are static, declare the class itself static - just like the System.Math class, so you cannot create instances at all.
You could make your calcResultFromDoubleArray method static, and then call it via MyMath.calcResultFromDoubleArray(val1, val2)
In your code there is not really a point of creating an instance of MyMath class. You can make the methods static
public static double[] doubleArrayXY(string inputValue) { ... }
public static double calcResultFromDoubleArray(double one, double two) { ... }
and call them like so
double[] retD = MyMath.doubleArrayXY(s);
double result = MyMath.calcResultFromDoubleArray(retD[0], retD[1]);
If you make your methods static you can do the following in your main class:
double result = MyMath.calcResultFromDoubleArray(MyMath.doubleArrayXY(s));
And change calcResultFromDoubleArray to take the array rather than two values (as its title suggests).
FYI you can also chain String operations because they return Strings as such:
string[] res = inputValue.ToLower().Split(new string[] { "y" }, StringSplitOptions.None);
No need to create double x and double y. Change the last part of the method to:
return new double[] {double.Parse(resx), double.Parse(res[1]};
While changes such as these (there are more, there often are) will be minimal increases in performance, they will increase it a bit (the most from the static part - new is relatively expensive).
Most importantly though, they make the code more readable and elegant.
It looks to me like the two methods on MyMath could (or possibly should) both be static since they rely on nothing at all outside the method. Quite often this is the case with things like Maths libraries. It seems others have said this too though.
In addition you may be better off to create a class or struct to represent your X/Y. It may be that it isn't appropriate but if it represents a thing then you might want a class to represent that thing as well. See for example the Point and PointF classes. I'd suggest one of these but they don't have the same precision that you are using (and your X/Y may not be points so it might not be appropriate)
Also the line you said didn't work:
double result = dRet01.calcResultFromDoubleArray(retD[0], retD[1]);
This should have worked with the code as shown. What error were you getting on it? dRet01 exists and so it should have worked just as well as creating a new instance. The comments that it should be static are most applicable but if you are new to C# I thought it worth pointing this out so you don't build up any wrong ideas about what is and isn't possible. :)
Related
Relative newcomer to c# here.
Let’s say I have 50 different methods a1(), a2(), … a50() and I want to call a random one. One way to do it is of course to generate a random int, nr, between 1 and 50 and then use a lot of if statements like if(nr == 1){
a1()
} and so on. Quite cumbersome - can I do something smarter?
Is it for example possible to do something along the lines of creating a string which is initially only “a” and then adding nr as a string and then calling that string as method? Like this:
Public void RandomMethod()
{
nr = Random.Range(1,51);
string = ‘a’ + nr.tostring();
string();
}
I know this doesn’t work, but something like this instead of my first idea would save me hundreds of lines of code
Any response is appreciated 😊
One option would be to put your functions into a collection, say a List for example. Then you could randomly index into that collection to get a random function to call. You would generate a random index between 0 and the length of the List minus 1. This could apply generally to any number of functions then (50 or otherwise).
To do exactly what you asked (and, I have no clue why you'd want to), consider something like this:
Create a delegate that matches the call signature of all of your methods (they all have to have the same call signature or ... I really can't imagine what you'd want to do if they didn't). You could use an Action or Func declaration, but I'm going to make it clear here:
public delegate void SomeMethod(int i);
Then write your 50 methods. All their call signatures will match the delegate:
public static void Method1(int i) { System.Console.WriteLine($"{nameof(Method1)}: {i}"); }
public static void Method2(int i) { System.Console.WriteLine($"{nameof(Method2)}: {i}"); }
public static void Method3(int i) { System.Console.WriteLine($"{nameof(Method3)}: {i}"); }
public static void Method4(int i) { System.Console.WriteLine($"{nameof(Method4)}: {i}"); }
// ...
public static void Method50(int i) { System.Console.WriteLine($"{nameof(Method50)}: {i}"); }
Then create an array of delegates:
public static SomeMethod[] Methods = new SomeMethod[]
{
Method1,
Method2,
Method3,
Method4,
//...
Method50,
};
And then a method that picks 1 or more from the list at random and runs them:
public void Run5RandomMethods()
{
Random random = new Random();
for(int i = 0; i < 5; i++)
{
var randNumber = random.Next(50);
var method = Methods[randNumber];
method.Invoke(i);
}
}
Note: this is untested, I'm not going to create 50 dummy methods for you. If you find an issue, comment below and I'll fix the code
By the way, what you show in your question (composing the name of the method by concatenating a string and the string representation of a number) is doable using a technology known as Reflection. Let me know if you really want to do that.
So, assuming we have fifty methods that all have a signature like
void SomeMethod()
{
...
}
You could declare an array like below, this is an array of Action delegates
var methods = new Action[]
{
SomeMethod,
SomeOtherMethod,
() => _ = SomeFunctionWithAHardcodedParameter("Wibble"),
...
}
Then you could call a random method by doing,
method[Random.Next(methods.Length)]();
First off, I just want to say something similar to what others have already said: you should readdress whether you need 50 methods named a1(), a2(), ..., a50(), and rethink what the problem you're trying to solve is (which you haven't provided enough information for us to help you with).
If that was hyperbole, try to avoid doing that; it may muddy the responses to solve a perceived problem ("why do you have 50 poorly-named methods?") instead of your actual problem ("can I execute a randomly selected method?" <- still a weird question, but who am I to judge...).
That out of the way, you can use something like Reflection. This can be "dangerous" and expensive when executing, so use with caution... or better yet don't use it, but be aware of it, because it can lead you to think Reflection is the answer to problems you don't actually have.
Anyway, you can:
// have an instance of an object
var obj = new ClassName();
// get all the methods of the object
var methodInfos = typeof(ClassName).GetMethods();
// filter them somehow
var filteredMethodInfos = methodInfos.Where(m => Regex.IsMatch(m.Name, #"\a[\d]{1,2}")).ToArray();
// get a random one and invoke it
var rnd = new Random();
filteredMethodInfos[rnd.Next(filteredMethodInfos.Length)].Invoke(obj, null);
I haven't tested this, but it should in theory work.
But again: don't use reflection if you don't have to. There's probably an issue with your root question (as Tim Schmelter said, this is an "XY-problem") if your answer is "randomly execute 1 of 50 methods".
Been bouncing back and forth between Swift and C# and I'm not sure if I'm forgetting certain things, or if C# just doesn't easily support what I'm after.
Consider this code which calculates the initial value for Foo:
// Note: This is a field on an object, not a local variable.
int Foo = CalculateInitialFoo();
static int CalculateInitialFoo() {
int x = 0;
// Perform calculations to get x
return x;
}
Is there any way to do something like this without the need to create the separate one-time-use function and instead use an instantly-executing lambda/block/whatever?
In Swift, it's simple. You use a closure (the curly-braces) that you instantly execute (open and closed parentheses), like this:
int Foo = {
int x = 0
// Perform calculations to get x
return x
}()
It's clear, concise and doesn't clutter up the object's interface with functions just to initialize fields.
Note: To be clear, I do NOT want a calculated property. I am trying to initialize a member field which requires multiple statements to do completely.
I wouldn't suggest doing this, but you could use an anonymous function to initialize
int _foo = new Func<int>(() =>
{
return 5;
})();
Is there a reason you would like to do it using lambdas rather than named functions, or as a calculated property?
I assume you want to avoid calculated properties because you want to either modify the value later, or the computation is expensive and you want to cache the value.
int? _fooBacking = null;
int Foo
{
get
{
if (!_fooBacking.HasValue)
{
_fooBacking = 5;
}
return _fooBacking.Value;
}
set
{
_fooBacking = value;
}
}
This will use what you evaluate in the conditional the first time it is gotten, while still allowing the value to be assigned.
If you remove the setter it will turn it into a cached calculation. Be careful when using this pattern, though. Side-effects in property getters will be frowned upon because they make the code difficult to follow.
To solve the problem in the general case you'd need to create and then execute an anonymous function, which you can technically do as an expression:
int Foo = new Func<int>(() =>
{
int x = 0;
// Perform calculations to get x
return x;
})();
You can clean this up a bit by writing a helper function:
public static T Perform<T>(Func<T> function)
{
return function();
}
Which lets you write:
int Foo = Perform(() =>
{
int x = 0;
// Perform calculations to get x
return x;
});
While this is better than the first, I think it's pretty hard to argue that either is better than just writing a function.
In the non-general case, many specific implementations can be altered to run on a single line rather than multiple lines. Such a solution may be possible in your case, but we couldn't possibly say without knowing what it is. There will be cases where this is possible but undesirable, and cases where this may actually be preferable. Which are which is of course subjective.
You could initialize your field in the constructor and declare CalculateInitialFoo as local function.
private int _foo;
public MyType()
{
_foo = CalculateInitialFoo();
int CalculateInitialFoo()
{
int x = 0;
// Perform calculations to get x
return x;
}
}
This won't change your code too much but you can at least limit the scope of the method to where it's only used.
I am trying to split a string and assign the different values. The string it returns to me is:
0077|PCK|PRD|05025066840471|4|Can Opener|1|10|B|20.00|0|100|0|0.00|0|0|1|0|0
So I want to split the string on "|" and assign each of them to another variable. That is what I tried to do:
public static void LoadPRD(string sData)
{
string[] s = null;
prdType PRD = new prdType();
s = sData.Split("|");
PRD.bCode = s.Left(s[0], 14);
PRD.PCode = s.Left(s[1], 12);
PRD.Desc = s.Left(s[2], 40);
PRD.Pack = s.Val(s[3]);
PRD.Unit = s.Left(s[4], 12);
PRD.VATCode = s.Left(s[5], 1);
PRD.VATRate = Conversion.Val(s[6]);
PRD.Cost = Conversion.Val(s[7]);
PRD.Sell = Conversion.Val(s[8]);
PRD.Stock = Conversion.Val(s[9]);
PRD.AWS = Conversion.Val(s[10]);
PRD.OnOrder = Conversion.Val(s[11]);
PRD.OrderQty = Conversion.Val(s[12]);
PRD.LabelQty = Conversion.Val(s[13]);
PRD.Restriction = s.Left(s[14], 1);
PRD.MinStock = s.Val(s[15]);
PRD.PromoCode = s.Left(s[16], 3);
PRD.MnM = s.Left(s[17], 3);
}
The error message says that the Strings does not exist in the context, but it is not too of a helpful information, I do understand what it means but I am very confused on how to approach the solution.
Just so you know, I did create the variable before hand, I've posted them below:
public struct prdType
{
public string bCode;
public string PCode;
public string Desc;
public Int16 Pack;
public string Unit;
public string VATCode;
public float VATRate;
// Stored in pence
public long Cost;
public long Sell;
public long Stock;
public float AWS;
public long OnOrder;
public long OrderQty;
public long LabelQty;
public string Restriction;
public long MinStock;
public string PromoCode;
}
Your help will be much appreciated.
Thanks.
EDIT:
On
s = sData.Split("|");
it says: "The best overloaded method match for string.Split(params char[]) has some invalid arguments. It also says that arguments cannot be converted to char. Any ideas?
Rather than use legacy VB methods for this, I would suggest using C# methods all the way.
string[] s = sData.Split('|');
The use of Strings.Left is not readily apparent. Since you've already split the line, you'll have each element of the split in its entirety. If you want to take only the first n characters, you can do that, but there is no built-in equivalent for Strings.Left in C#.
For those elements that are a different type, you can use Convert.ToX:
PRD.Pack = Convert.ToInt16(s[3]));
PRD.VATRate = Convert.ToSingle(s[6]));
PRD.Cost = Convert.ToInt64(s[7]);
And so on. Note that float uses Convert.ToSingle, not Convert.ToFloat.
ADDED
Based on #Raphael's comment, Convert.ToX is not a direct replacement for Conversion.Val(), but as long as the string is strictly numeric you will be ok and will get the correct type.
These methods come from Microsoft.VisualBasic namespace.It should be only used if you know what you're doing (see Tim's comment on this answer).
I wouldn't advise you to use these methods.
They are equivalent methods in c# (or they're rather easy to implement).
Like String.Split, for example (so you could do var s = sData.Split('|'); )
A way to do something equivalent to String.Left
Wouldn't advise to do this, but anyway :
If you want absolutely use them, you should :
Add a reference to Microsoft.VisualBasic assembly (right click on project's references, you should find it in Framework libs)
Add the right using at the top of your code : using Microfost.VisualBasic;
You need to do s = sData.Split('|');
I get from an input a group of double variables named: weight0, weight1...weight49.
I want to dynamically insert them into a double Array for easier manipulation.
But instead of calling each one like: Weights[0] = weight0...Weights[49] = weight49 I want to do it with a single loop.
Is there a way to do it?
No, basically - unless you mean at the same time that you create the array:
var weights = new[] {weight0, weight1, weight2, ... , weight48, weight49};
Personally, I'd be tempted to get rid of the 50 variables, and use the array from the outset, but that may not be possible in all cases.
you could use reflection to determine the index of the array from the variable names but this is far from efficient. See this post for details.
I would try to do it with a KeyValuePair- Listobject
// sample data
var weight = 1.00;
// create a list
var tmp = new List<KeyValuePair<string,object>>();
// Here you can add your variables
tmp.Add(new KeyValuePair<string,object>("weights" + tmp.Count.ToString()
, weight));
// If needed convert to array
var weights = tmp.ToArray();
// get the information out of the array
var weightValue = weights[0].Value;
var weightKey = weights[0].Key;
I think this will give you all the options, you might need for the array. Give it a try.
I'm putting this up because you can do it - so long as these variables are actually fields/properties. Whether you should is another matter - this solution, while reusable, is slow (needs delegate caching) and I have to say I agree with Marc Gravell - consider using an array throughout if you can.
If the variables are properties then it needs changing. Also if you need to write the array back to the variables in one shot (because this solution generates an array with copies of all the doubles, I wouldn't consider creating an object array with boxed doubles), that requires another method...
So here goes. First a holy wall of code/extension method:
//paste this as a direct child of a namespace (not a nested class)
public static class SO8877853Extensions
{
public static TArray[] FieldsToArray<TObj, TArray>(this TObj o,string fieldPrefix)
{
if(string.IsNullOrWhiteSpace(fieldPrefix))
throw new ArgumentException("fieldPrefix must not null/empty/whitespace",
"fieldPrefix");
//I've done this slightly more expanded than it really needs to be...
var fields = typeof(TObj).GetFields(System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.NonPublic)
.Where(f =>f.Name.StartsWith(fieldPrefix) && f.FieldType.Equals(typeof(TArray)))
.Select(f =>new{ Field = f, OrdinalStr = f.Name.Substring(fieldPrefix.Length)})
.Where(f => { int unused; return int.TryParse(f.OrdinalStr, out unused);})
.Select(f => new { Field = f.Field, Ordinal = int.Parse(f.OrdinalStr) })
.OrderBy(f => f.Ordinal).ToArray();
//doesn't handle ordinal gaps e.g. 0,1,2,7
if(fields.Length == 0)
throw new ArgumentException(
string.Format("No fields found with the prefix {0}",
fieldPrefix),
"fieldPrefix");
//could instead bake the 'o' reference as a constant - but if
//you are caching the delegate, it makes it non-reusable.
ParameterExpression pThis = Expression.Parameter(o.GetType());
//generates a dynamic new double[] { var0, var1 ... } expression
var lambda = Expression.Lambda<Func<TObj, TArray[]>>(
Expression.NewArrayInit(typeof(TArray),
fields.Select(f => Expression.Field(pThis, f.Field))), pThis);
//you could cache this delegate here by typeof(TObj),
//fieldPrefix and typeof(TArray) in a Dictionary/ConcurrentDictionary
return lambda.Compile()(o);
}
}
The extension method above will work on any type. It's generic over both the instance type and desired array type to simplify the creation of the lambda in code - it doesn't have to be generic though.
You pass in the name prefix for a group of fields - in your case "weight" - it then searches all the public and private instance fields for those with that prefix that also have a suffix which can be parsed into an integer. It then orders those fields based on that ordinal. It does not check for gaps in the ordinal list - so a type with weight0 and weight2 would work, but would only create a two-element array.
Then it bakes a dynamic piece of code using Expression trees, compiles it (at this point, as mentioned in the code, it would be good to cache the delegate against TObj and TArray for future use) and then executes it, returning the result.
Now add this to a test class in a standard unit test project:
private class SO8877853
{
private double field0 = 1.0;
private double field1 = -5.0;
private double field2 = 10.0;
public double[] AsArray()
{
//it would be nice not to have to pass both type names here - that
//can be achieved by making the extension method pass out the array
//via an 'out TArray[]' instead.
return this.FieldsToArray<SO8877853, double>("field");
}
}
[TestMethod]
public void TestThatItWorks()
{
var asArray = new SO8877853().AsArray();
Assert.IsTrue(new[] { 1.0, -5.0, 10.0 }.SequenceEqual(asArray));
}
Like I say - I'm not condoning doing this, nor am I expecting any +1s for it - but I'm a sucker for a challenge :)
my problem is as follows:
Im building a console application which asks the user for the numbers of objects it should create and 4 variables that have to be assigned for every object.
The new objects name should contain a counting number starting from 1.
How would you solve this?
Im thinking about a class but im unsure about how to create the objects in runtime from userinput. Is a loop the best way to go?
What kind of class, struct, list, array .... would you recommend. The variables in the object are always the same type but i need to name them properly so I can effectivly write methods to perform operations on them in a later phase of the program.
Im just learning the language and I would be very thankful for a advice on how to approach my problem.
If I understand your problem correctly:
class MyClass
{
public int ObjectNumber { get; set; }
public string SomeVariable { get; set; }
public string AnotherVariable { get; set; }
}
// You should use keyboard input value for this
int objectsToCreate = 10;
// Create an array to hold all your objects
MyClass[] myObjects = new MyClass[objectsToCreate];
for (int i = 0; i < objectsToCreate; i++)
{
// Instantiate a new object, set it's number and
// some other properties
myObjects[i] = new MyClass()
{
ObjectNumber = i + 1,
SomeVariable = "SomeValue",
AnotherVariable = "AnotherValue"
};
}
This doesn't quite do what you described. Add in keyboard input and stuff :) Most of this code needs to be in some kind of Main method to actually run, etc.
In this case, I've chosen a class to hold your 4 variables. I have only implemented 3 though, and I've implemented them as properties, rather than fields. I'm not sure this is necessary for your assignment, but it is generally a good habit to not have publically accessible fields, and I don't want to be the one to teach you bad habits. See auto-implemented properties.
You mentioned a struct, which would be an option as well, depending on what you want to store in it. Generally though, a class would be a safer bet.
A loop would indeed be the way to go to initialize your objects. In this case, a for loop is most practical. It starts counting at 0, because we're putting the objects in an array, and array indexes in C# always start at 0. This means you have to use i + 1 to assign to the object number, or the objects would be numbered 0 - 9, just like their indexes in the array.
I'm initializing the objects using object initializer syntax, which is new in C# 3.0.
The old fashioned way would be to assign them one by one:
myObjects[i] = new MyClass();
myObjects[i].ObjectNumber = i + 1;
myObjects[i].SomeVariable = "SomeValue";
Alternatively, you could define a constructor for MyClass that takes 3 parameters.
One last thing: some people here posted answers which use a generic List (List<MyClass>) instead of an array. This will work fine, but in my example I chose to use the most basic form you could use. A List does not have a fixed size, unlike an array (notice how I initialized the array). Lists are great if you want to add more items later, or if you have no idea beforehand how many items you will need to store. However, in this case, we have the keyboard input, so we know exactly how many items we'll have. Thus: array. It will implicitly tell whoever is reading your code, that you do not intend to add more items later.
I hope this answered some questions, and raised some new ones. See just how deep the rabbit hole goes :P
Use a list or an array. List example:
int numberOfObjects = 3;
List<YourType> listOfObjects = new List<YourType>();
for(int i = 0 ; i < numberOfObjects ; i++ )
{
// Get input and create object ....
// Then add to your list
listOfObjects.Add(element);
}
Here, listOfObjects is a Generic list that can contain a variable number of objects of the type YourType. The list will automatically resize so it can hold the number of objects you add to it. Hope this helps.
If I understood what you are asking you could probably do something like this:
class Foo
{
private static int count;
public string name;
public Foo(...){
name = ++count + "";
}
}
I'm guessing what you're trying to do here, but this is a stab in the dark. The problem I'm having is dealing with the whole "the new objects name should contain a counting number starting from 1" thing. Anyway, here's my attempt:
public class UserInstantiatedClass
{
public int UserSetField1;
public int UserSetField2;
public int UserSetField3;
public int UserSetField4;
public string UserSpecifiedClassName;
}
public static class MyProgram
{
public static void Main(string [] args)
{
// gather user input, place into variables named
// numInstances, className, field1, field2, field3, field4
List<UserInstantiatedClass> instances = new List< UserInstantiatedClass>();
UserInstantiatedClass current = null;
for(int i=1; i<=numInstances; i++)
{
current = new UserInstantiatedClass();
current.UserSpecifiedClassName = className + i.ToString(); // adds the number 1, 2, 3, etc. to the class name specified
current.UserSetField1 = field1;
current.UserSetField2 = field2;
current.UserSetField3 = field3;
current.UserSetField4 = field4;
instances.Add(current);
}
// after this loop, the instances list contains the number of instances of the class UserInstantiatedClass specified by the numInstances variable.
}
}