I have made a little calculator:
private void button1_Click(object sender, EventArgs e)
{
int input1 = int.Parse(textBox1.Text);
int input2 = int.Parse(textBox2.Text);
int Result = input1 + input2;
textBox3.Text = Result.ToString();
}
Why can't I just do textBox3.Text = Result; when I already told them that the result is int type in the line before?
When I need to explain data types, I often use the analogy with shapes.
A data type is a shape, that forms the behaviour of the variable of the specified type. When a variable of a given type is created it holds the description of the type and a value. Variables with the same shape can be connected together with the help of operators (for example +).
Two variables from a different type (shape) can not be connected directly together - they need a converter / wrapper.
A converter makes for example from the shape triangle a circle or a wrapper masks the triangle as a circle.
Back to your example. TextBox controls can hold only the data type string, meaning they are incompatible with the shape of an int. You already have converted the content of the string to an int using int input1 = int.Parse(textBox1.Text);.
That is why you can not simply assign the Result variable to the Text property - their shapes are different, so you need to convert the int back to string using the ToString() method. You could also write textBox3.Text = (input1 + input2).ToString();.
The shape analogy can be used to understand parameters passing - as long you know the signature of a method int add(int a, int b), you know exactly what you need to put when you are calling a method (two int's) and what kind of type to expect as a result (an int). For example String result = add(1,2); will not work because the signature is not as expected, result should be of type int in order to work (int result = add(1,2);) or the call to add(1,2) should be converted to string (string result = add(1,2).ToString();).
Same goes with classes and objects - a class is a custom data type, so a custom shape. As long two instances of a class (objects) have the same shape they can be connected or assigned to each other.
This is a very simplified explanation (but still it helped my trainee in the past) so take your time and have a look at the C# MSDN documentation for a thorough explanation of data types.
Why can't I just do textBox3.Text = Result; when I already told them
that the result is int type in the line before?
Even though you 'told' that the result would be of type int, the compiler needs to know how to interpret/transform the string into an int.
int.Parse is one way of doing just that.
Sounds like you may want to start here with C# Data Types. As for your question. TextBox.Text is of type string. Check out MSDN articles for the different controls that you're using and their properties, such as this MSDN Article on TextBox.Text
textBox3.Text is a type of string while Result is a type of int and in your code you are assigning int value to a string which is wrong. You need to transform ones type to the other.
Related
I have a database which stores user inputs in an abstract stringified form. These user inputs have a varchar column which describes its type (string, decimal, bool, dropdown etc).
Now this get's send to the front end to display some input elements in the browser. This works great!
However since the input is so generic the value is also a varchar. The problem I am facing is that I need to do some validation on the value. (e.g. some string input have a maxLength or regex specified, a decimal can have a min and max value).
so once I get back the value the user entered it is in string format and I want to parse it to the correct native type so I can start validating it.
I would like a function which returns the parsed value in it's correct type.
so I would have a function which is something like this:
public {something here} ParseValue(InputObject object, string type) {
// parse here based on type
// InputObject has a few properties like value, min, max, regex etc
// all as a string.
// for instance if type is datetime I want to return a new object
// which has parsed the value, min and max as datetime.
// it should also be possible for the type to be decimal and min, max
// and value should be decimal in the outputObject
}
I am coming from a dynamically typed background so I have no idea how to do something like this. or even if it is possible.
any help is appreciated!
You'd be best off if you don't directly try to evaluate the type by the Database-Datatype and instead store the "real" type in a seperate DB-Column. Except if you build an association between C#-Types and Database-Types because you can do something like this then:
String val = "123";
String type = "System.Int32";
Type tempType = Type.GetType(type);
if (tempType == null)
return null;
dynamic result = Convert.ChangeType(val, tempType);
Of course this would be applicable to the boundary values also. Note that Convert.ChangeType only works for very popular Types and is not universally useable and that it throws an Exception if theres something failing which need to be catched also.
What you could do is create an interface IValidatable that defines a method like Validate(). Then you could use that as a return type. Then you just parse your value using a switch (probably delegate this to some method or class) to an implementation of IValidatable. E.g.
public interface IValidatable {
bool Validate();
}
public class ValidateableInteger : IValidatable {
private int _value;
public ValidateableInteger(int i) {
_value = i;
}
bool Validate() {
//code where you validate your integer.
}
}
Note that this is not very flexible as you only have 1 method called validate, though clearly you can define multiple more generic methods that could implement different validations.
Moreover you can create more specific interfaces for e.g. numeric types (e.g. IValidateableNumeric and ValidateableInt : IValidateableNumeric)
Note that you're basically typing your input here though, which is kindof weird and unnecessary given the fact that you can just work with typed data to begin with.
In the end I would discourage people from bypassing type system this way. In this case especially there are plenty better ways of creating form elements while using typed data (checkout the Razor template engine).
I'm trying to make a basic calculator in c#.
The only problem is, I don't know how I could add numbers to an int; for instance, if I wanted button1 to do something like this in a textbox, it'd be
textBox1.text += "1"
but this is for the operations, and the textbox displays the operator, so I couldn't convert it to an int. I'd really appreciate some help.
You can do it with something like (where s is a string):
s = (Int32.Parse(s) + 1).ToString();
Just make sure that s is actually a valid number, otherwise you'll have to cobble together something with TryParse and figure out what to do when it's not a number, like leave it alone:
int val;
if (Int32.TryParse(s, out val)) {
val++;
s = val.ToString();
}
You can also restrict user input so that they can only enter integers, have a look at MaskedTextBox and set the Mask property. See the documentation here.
C# is a strongly typed language. A textbox contains a string, which you must convert to an int before performing arithmetical operations.
Converting a string to an int can be done with int.Parse(), then you must convert back to a string to change the textbox contents:
int temp = int.Parse(textBox1.Text) + 1;
textBox1.Text = temp.ToString();
This will throw an exception if textBox.Text cannot be converted to an int. To deal with this, look up the int.TryParse() function.
I just did a little experiment to see if altering an un-boxed variable would propagate changes made to the original source and got two completely different results depending on the types that I used. I am mainly interested in figuring this out for WPF data binding applications in which I bind to objects, cast, change, and hope that the original's update their UIs.
My results were as follows.
Simple types seem to lose their reference to the original source after un-boxing.
Custom types seem to keep their reference.
It seems that I don't have anything to worry about in my scenario of hoping that my WPF UI updates itself after making changes to unboxed bound data contexts; however, not knowing WHY this happens only with complex objects worries me a bit. I do not want my UI to fail on rare or odd occasions I do not know about. Can anyone explain what the heck is mechanically going on back there?
class Program
{
//simple types
private static object sbox1;
private static object sbox2;
private static int svalue1 = 10;
private static int svalue2 = 15;
//custom types
private static MyType cvalue1;
private static MyType cvalue2;
private static object cbox1;
private static object cbox2;
static void Main(string[] args)
{
//Box up the values
sbox1 = svalue1;
sbox2 = svalue2;
//unbox the values to local var
var sunboxed1 = (int)sbox1;
var sunboxed2 = (int)sbox2;
//change the values in the new unboxed vars
sunboxed1 = -10;
sunboxed2 = -15;
//check unboxed values and check original value variables
Console.WriteLine("unboxed1 = " + sunboxed1);
Console.WriteLine("unboxed2 = " + sunboxed2);
Console.WriteLine("value1 = " + svalue1);
Console.WriteLine("value2 = " + svalue2);
//Now try hand at custom types
cvalue1 = new MyType() { Example = "I am cvalue1's original string." };
cvalue2 = new MyType() { Example = "I am cvalue2's original string." };
//now box them up.
cbox1 = cvalue1;
cbox2 = cvalue2;
//now unbox and change the strings
var cunboxed1 = cbox1 as MyType;
var cunboxed2 = cbox2 as MyType;
//change the original strings to see if they propogate to original objects
cunboxed1.Example = "I am cunboxed1's altered string.";
cunboxed2.Example = "I am cunboxed2's altered string.";
//print unboxed and originals values to compare
Console.WriteLine("cunboxed1.Example = " + cunboxed1.Example);
Console.WriteLine("cunboxed2.Example = " + cunboxed2.Example);
Console.WriteLine("cvalue1.Example = " + cvalue1.Example);
Console.WriteLine("cvalue2.Example = " + cvalue2.Example);
Console.ReadKey();
}
}
class MyType
{
public string Example { get; set; }
}
Results from the tester app:
unboxed1 = -10
unboxed2 = -15
value1 = 10
value2 = 15
cunboxed1.Example = I am cunboxed1's altered string.
cunboxed2.Example = I am cunboxed2's altered string.
cvalue1.Example = I am cunboxed1's altered string.
cvalue2.Example = I am cunboxed2's altered string.
What you're seeing is caused by the different handling of value and reference types. In the first example, you are boxing an int. This is wrapped in Int32, a value type, and assigned to your object variable. In your unboxing step, the original Int32 object is copied, because it is a value type, and its value is assigned to your int variable sunboxed1. sbox1 and sunboxed1 hold different values and exist at different memory locations, so no change made to one will affect the other.
In your second example, you are assigning a class to an object variable. This isn't boxing it; you're simply upcasting a reference to your object. When you subsequently downcast it back to MyType with the as keyword, you get a reference to the original object. So, cvalue1 and cunboxed1 hold a reference to the same object.
As dotnetom stated this is more about value vs reference types.
According to MSDN http://msdn.microsoft.com/en-us/library/t63sy5hs.aspx
A data type is a value type if it holds the data within its own memory allocation. Value types include the following:
All numeric data types....
However, for classes:
A reference type contains a pointer to another memory location that holds the data. Reference types include the following: Class types, such as Form.....
With the last line being the most interesting.
A class is a reference type. For this reason, reference types such as Object and String are supported by .NET Framework classes. Note that every array is a reference type, even if its members are value types.
This is why the custom types above changed the original values above after un-boxing. strings themselves are reference types so it it might seem that the reason changes were propogated was due to me using a string as an example and not a numeric type; however, changing the Example property to an int will still change the original source as well and yield the same results.
For example if both values are int type it adds them.... ie 2+2=4
if both values are float....ie 2.2+2.3=4.5
or if one value is string and second is int...ie 1 + Pak=1Pak
We will get these two values from user using tfwo textboxes
This would be one way of doing it. Without having to convert to string and than back to numeric.
public object Add(IConvertible a, IConvertible b)
{
if(IsNumeric(a) && IsNumeric(b))
return a.ToDouble(CultureInfo.InvariantCulture) + b.ToDouble(CultureInfo.InvariantCulture);
return a.ToString() + b.ToString();
}
public static bool IsNumeric(object o)
{
var code = (int)Type.GetTypeCode(o.GetType());
return code >= 4 && code <= 15;
}
You can't do it using generics. You'll receive string from your textbox anyway. The only thing to do is to implement it "manually" exactly this way as you said:
public string TrySumTwoStrings(string input1, string input2)
{
double numeric1, numeric2;
if (Double.TryParse(input1, out numeric1) && Double.TryParse(input2, out numeric2))
return (numeric1 + numeric2).ToString();
return input1 + input2;
}
There's no way to use generics if we have no different types (everything is typed as string here).
You wouldn't, generics cannot be constrained in a way to support arithmetic operators (or concatenation). You would need to create overloads.
public int Add(int x, int y)
public double Add(double x, double y)
public decimal Add(decimal x, decimal y)
// etc.
Of course, you still have the problem of determining how exactly to parse your data. The source being a TextBox, the data will inherently be strings. You will have to determine which type of number it should be, if any.
If doing this for a real application, you shouldn't have this problem. Your textbox should be expected to receive input from the user in the form of an integer, or a decimal, or a string, etc. If it's not convertible to the proper type, it's an invalid input from your user. You wouldn't want the input to have to be magically deduced.
string Str1 = textBox1.Text.Trim();
string Str2 = textBox2.Text.Trim();
double Num1,num2;
bool isNum1 = double.TryParse(Str1, out Num1);
bool isNum2 = double.TryParse(Str2, out Num2);
if (isNum1 && isNum2)
MessageBox.Show((isNum1 + isNum2).ToString());
else
MessageBox.Show( Str1 + Str2);
Check out http://www.yoda.arachsys.com/csharp/miscutil/ The MiscUtil library. It contains some very clever Expression Tree stuff to allow operators with generics. It's not going to work exactly how you want (as others have stated, you can't constrain types to have operators) but it should do exactly what you want.
I don't know how it handles adding different types together though, I've not tried that.
I would think it would take some processing the values before hand in order with things like String.PArse, Int.Parse, etc...
Take them in order of compplexity first because 1 will convert to string, however x will not convert to integer or float.
Officially changed my answer to same as comment...
Best suggestion I have on that would be allow the user to select what type to interpret the data as and pass to the appropriate function based on what the user meant, there would be too many ways to interprets char strings to know what the users intention was, code processes logic not intent.
I have the following piece of code
List<String> l = new List<String>();
String s = "hello";
l.Add(s);
s = "world";
When I set up some breakpoints and go through the program, after executing the last line, the value in the list is still hello instead of world.
Shouldn't it equal world ? Isn't a string an object, and am I not just inserting a pointer into the list? Later on if I change the string to point to a different value ("world"), why is my list still referencing the old value?
How can I get my desired effect ?
Thanks a lot!
Strings are immutable so that won't work. When you attempt to set into it, you actually drop the pointer to the old string and create a new one under the hood.
To get the desired effect, create a class that wraps a string:
public class SortOfMutableString
{
public string Value {get;set;}
public SortOfMutableString(string s)
{
Value = s;
}
public static implicit operator string(SortOfMutableString s)
{
return s.Value;
}
public static implicit operator SortOfMutableString(string s)
{
return new SortOfMutableString(s);
}
}
And use this in your list. Then references will point to the class, but you can contain the string value inside. To make it even better, override implicit casting to and from string so you don't even need to see that you are talking to a SortOfMutableString.
Refer to Jon Skeet's answer for undoubtedly a very accurate explanation about string's in C#, I'm not even going to bother!
Alternative class names:
PseudoMutableString
ICantBelieveItsNotMutable
HappyAndReferenceableString
You're changing the s reference to refer to a different String instance.
Strings are immutable; it is impossible to change the existing instance that you added to the list.
Instead, you can create a mutable StringHolder class with a writable String property.
No, it shouldn't equal world. The value of the variable s is a reference. When you call l.Add(s), that reference is passed by value to the list. So the list now contains a reference to the string "hello".
You now change the value of s to a reference to the string "world". That doesn't change the list at all.
It's important to distinguish between three very different concepts:
A variable (which has a name and a value)
A reference (a value which allows you to navigate to an object, or null)
An object
So in particular, the list doesn't know anything about the variable s - it knows about the value which was passed into Add; that value happened to be the value of s at the time Add was called, that's all.
You may find these articles helpful:
Values and references
Parameter passing in C#
No, there are two different references involved. One called s and one that's at List[0]. When you say l.Add(s) you are setting the list reference to the same address as s, but then when you assign s to "world", then s will point to the new string, leaving List[0] pointing to the old string.
If you really want to do something like what you are asking, you'd need to wrap the string in another object that contains a string, so that s and List[0] both refer to that object, and then that object's reference to a string can change and both will see it.
public class StringWrapper
{
public string TheString { get; set; }
}
Then you can do:
var s = new StringWrapper { TheString = "Hello" };
var l = new List<StringWrapper>();
l.Add(s);
s.TheString = "World";
And now l[0].TheString will be world too. This works because in this case we are not changing the reference in List[0] or s, but they contents of the object referred to by s and List[0].
A variable is an object reference, not an object itself. s = "world" says "make s refer to the string "World") - it does not in any way affect the string "hello" that s was previously referring to. Furthermore, strings in C# are always immutable. You can, however, make the first list element (which currently refers to "hello") refer to a different string: l[0] = "world".
The other two answers here did a great job of saying why what you tried didnt' work, but you were looking for a solution for your desired effect. Wrap a string (property) inside of an object. Then you can change that string and it will be reflected in the collection.