This doesn't work
public class Foo {
private int X { get; }
public Foo(string s) {
int.TryParse(s, out X);
}
}
but this works:
public class Foo {
private int X { get; }
public Foo(string s) {
int x;
int.TryParse(s, out x);
X = x;
}
}
What is the difference between the two, since the out parameter doesn't need to be initialised. Why the property cannot be passed as an out parameter?
I assume this is C# 6.0 because you have a get-only property.
It doesn't work because properties cannot be passed by reference. A function that takes a ref int or an out int parameter in C# is like a function that takes an int& in C++.
But an int property is not just an int at some address. A property can run any code it wants to in both the get and the set. And the language should not treat an auto-implemented property as special.
What if I wrote code like the following?
public class Foo {
private int X {
get { return 0; }
set { }
}
public Foo(string s) {
int.TryParse(s, out X);
}
}
There simply isn't any address of an int to pass into TryParse. The rules for whether the code is allowable are not permitted to look inside the get and set implementations.
Note that this works fine:
public class Foo {
private int X;
public Foo(string s) {
int.TryParse(s, out X);
}
}
When you use out, under the hood it's really a memory address that gets passed to the function that you call. A property is not a variable but a function and you cannot take its address so a property cannot be passed in place of an out parameter.
A member variable (or local variable) occupies memory and the compiler can take their address and pass it so it works with variables but not with properties.
Related
I'm trying to make default value for my struct.
For example default value for Int - 0, for DateTime - 1/1/0001 12:00:00 AM.
As known we can't define parameterless constructor in structure.
struct Test
{
int num;
string str;
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(default(Test)); // shows namespace and name of struct test.Test
Console.WriteLine(new Test()); // same
Console.ReadKey(true);
}
}
How can I make a default value for struct?
You can't. Structures are always pre-zeroed, and there is no guarantee the constructor is ever called (e.g. new MyStruct[10]). If you need default values other than zero, you need to use a class. That's why you can't change the default constructor in the first place (until C# 6) - it never executes.
The closest you can get is by using Nullable fields, and interpreting them to have some default value if they are null through a property:
public struct MyStruct
{
int? myInt;
public int MyInt { get { return myInt ?? 42; } set { myInt = value; } }
}
myInt is still pre-zeroed, but you interpret the "zero" as your own default value (in this case, 42). Of course, this may be entirely unnecessary overhead :)
As for the Console.WriteLine, it simply calls the virtual ToString. You can change it to return it whatever you want.
Your problem is not with the behaviour of C#/.Net. The way you instantiate the struct effectively creates an instance with default values for all member fields.
The Console.WriteLine converts its argument to a string using the ToString() method. The default implementation (Object.ToString()) simply writes the fully qualified class name (namespace and name, as you call it).
If you want another visualisation, you should override the ToString method:
public struct Test
{
int num;
string str;
public override string ToString()
{
return $"num: {num} - str: {str}";
}
}
This is my take on this in case somebody finds it useful.
public struct MyStruct
{
public int item1;
public float item2;
public float item3;
public static MyStruct Null => new MyStruct(-1, 0, 0);
}
I have a static method inside my struct so that I can do this:
var data = MyStruct.Null;
instead of
var data = new MyStruct();
data.item1 = -1;
...
Or create a custom constructor to pass the data.
Printing out objects of the C# results with namespaces unless you override .ToString() for your objects. Can you define your struct like below and try it ?
public struct Test
{
int num;
string str;
public override string ToString()
{
return "Some string representation of this struct";
}
}
PS: default(Test) gives you a struct contains default(int) and default(string) which I mean Test.num is 0 and Test.str is null
Hope this helps
You can also do this:
public struct MyStruct
{
public static readonly Default = new MyStruct(42);
public int i;
public MyStruct(int i)
{
this.i = i;
}
}
And then when you create a default struct of this type do this:
public MyStruct newStruct = MyStruct.Default;
But of course, this won't override default and other programmers will bump their heads a few times. Really consider if a struct is the way to go, from the microsoft docs:
"A structure type (or struct type) is a value type that can encapsulate data and related functionality. Typically, you use structure types to design small data-centric types that provide little or no behavior."
Consider this: if you had 2 values in your struct and you wanted to make constructors, would 2 or less constructors suffice? If the answer is no, then the answer is: don't use a struct.
What you probably want to do is to override ToString(), e.g.
struct Test
{
int num;
string str;
public override string ToString ()
{
return string.Format ($"{str} | {num}");
}
}
As you have mentioned, it is impossible to define default values for fields other than default values for their appropriate types. However, with an overriden ToString(), you will see better formatted information about your structure in the console and during debugging.
As you know, we can convert to string using Convert.ToString or ToString. I want to make the same thing for integer, byte etc. Furthermore, I want to see this method for every object when I put dot.
How should I write the method?
You are looking for a extension method. just create a static class and a static method inside it like:
public static class Exts
{
public static int ToInt32(this string x)
{
int result = 0;
int.TryParse(x, out result);
return result;
}
}
of course my method is a sample and it just returns 0 for any string value that is not castable to int, however you may write any code, accept default value as argument, throw exception,...
Then you can use it like:
string a = "123";
int b = a.ToInt32();
int c = "321".ToInt32();
Write a generic extension that converts any type to Int32:
public static class ObjectExt {
public static int ToInt<T>(this T obj) => Convert.ToInt32(obj);
}
This question already has answers here:
Is it possible to change the default value of a primitive data type?
(6 answers)
Closed 7 years ago.
I'm just curious to know, is it possible to change default value of e.g. int in C# and I can have a value -1 instead of 0.
public class Foo {
public int i;
}
...
foo = new Foo();
Console.Write(foo.i);
so this code must return
-1
Without explicit initializing
public class Foo {
public int i = -1;
}
Can I always be sure, that someone don't print somewhere something like
#define TRUE FALSE
but for default value of int
P.S. for interest purposes only.
No, basically. Assuming you don't initialize fields, the memory space is simply zeroed. You shouldn't expose fields directly anyway.
One trick I have seen to get around this (used by the capnp serializer, which works against raw memory, not objects) is to use xor. For example: if the default is -1, you can xor the value in and out:
public class Foo {
private int i;
public int I {
get { return i ^ -1; }
set { i = value ^ -1; }
}
}
This has no initialization, and does what you want. For use with types other than bools and integers this is more complex, but still possible - but it would be easier to use an initializer.
Note that for the -1 case, you could use "not" rather than "xor":
public class Foo {
private int i;
public int I {
get { return ~i; }
set { i = ~value; }
}
}
However: a field initializer (int i = -1;) or a constructor (public Foo() { i = -1; }) is probably simpler.
You can't change int's default value, but you can set Foo's variables default value:
public class Foo
{
public int i;
public Foo()
{
i = -1;
}
}
As far as I know, you can not change the default value of value types.
But you can certainly initialize it to a value you want.
for eg.
public class Foo {
public int i = -1;
}
...
foo = new Foo();
Console.Write(foo.i);
it will return
-1
A nice solution would be to override default(T), but you can't override this keyword. It is always null for reference types and zero for value types.
I want to replace the struct in the following code with a parent class with no data members and four subclasses, each subclass adds a different field. e.g. The SMValueFlt subclass adds a field named fltValue, and so on.
I am very new to C# and my Java is very rusty, so this is proving harder than I thought. And beyond actually setting up the class and subclasses i'm not sure how to proceed. Any help would be appreciated.
public class Interpreter {
enum TypeCode { None, IntType, FloatType, StringType };
struct SMValue {
public TypeCode t;
public int intValue;
public float fltValue;
public string strValue;
public SMValue( int i ) {
t = TypeCode.IntType; intValue = i; fltValue = 0.0F; strValue = null; }
public SMValue( float f ) {
t = TypeCode.FloatType; fltValue = f; intValue = 0; strValue = null; }
public SMValue( string s ) {
t = TypeCode.StringType; strValue = s; intValue = 0; fltValue = 0.0F; }
public override string ToString() {
if (t == TypeCode.IntType) return String.Format("{0}", intValue);
if (t == TypeCode.FloatType) return String.Format("{0}", fltValue);
if (t == TypeCode.StringType)
return strValue==null? "--null--" : strValue;
return "???";
}
}
}
I kept your TypeCode around in the first example, but it's not really necessary. You can inspect the type of a variable at runtime. For example,
var x = new SMFltValue() // (x.GetType() == typeof(SMFltValue)) = true, x is SMFltValue = true
Without using generics:
public enum TypeCode { IntType, FloatType, StringType };
public abstract class SMValue {
public TypeCode t;
public SMValue(TypeCode typeCode) {
t = typeCode;
}
public abstract string ToString();
}
public class SMFltValue : SMValue {
public float fltValue;
public SMFltValue(float f) : base(TypeCode.FloatType)
{
fltValue = f;
}
public override string ToString()
{
return String.Format("{0}", fltValue);
return String.Format("{0}", intValue);
return strValue==null ? "--null--" : strValue;
}
}
public class SMIntValue : SMValue {
public int intValue;
public SMIntValue(int i) : base(TypeCode.IntType)
{
intValue = i;
}
public override string ToString()
{
return String.Format("{0}", intValue);
}
}
public class SMStrValue : SMValue {
public string strValue;
public SMStrValue(string s) : base(TypeCode.StringType)
{
strValue = s;
}
public override string ToString()
{
return strValue==null ? "--null--" : strValue;
}
}
But generics would make it much nicer.
public class SMValue<T> {
public T value;
public SMValue(T value) {
this.value = value;
}
public string ToString() {
if (value == null)
{
return "--null--";
}
else
{
return string.Format("{0}", value);
}
}
}
Then you could use it as.
int i = 3;
float f = 5.0f;
string s = null;
new SMValue<int>(i).ToString() ==> 3
new SMValue<float>(f).ToString() ==> 5.0
new SMValue<string>(s).ToString() ==> "--null--"
The <int>, <float>, <string> aren't actually necessary because the compiler can infer the type from the variable being passed to the constructor.
The semantics of a struct with exposed fields are fundamentally different from those of a class. Fundamentally, each structure-type variable holds a bunch of fields stuck together with duct tape, while a class-type variable holds a not-necessarily-unique reference to a class object. If a structure type has two int fields, and one has two variables of that type, one has four integers which may be written independently. By contrast, if a class type has two int fields and one has two variables of that type, it's possible that the variables may at any given time reference different instances (in which case they would encapsulate a total of four independently-writable integers), or they may identify the same instance (in which case both variables would identify the same pair of integers, and so writing the first number in one pair would also write the first number in the other).
Some people think all types should behave like class objects, and regard as "evil" any types that don't. In reality, there are situations where it's useful to stick a bunch of variables together with duct tape (so they may be passed around as a unit when convenient), but guarantee that every bunch of variables is distinct. Class types can be used to mimic this behavior, awkwardly, but structures naturally work that way.
Without knowing exactly how you intend to use your type, it's hard to say whether a class will be able to fulfill your needs without having to rework all your client code. It's important to note, however, that any class used to replace a struct must almost always be immutable. If you can't easily convert your struct to a mutable class, you'll probably have to keep it a struct.
What's the Java equivalent of C#'s:
enum Foo
{
Bar = 0,
Baz = 1,
Fii = 10,
}
If you want attributes for your enum you need to define it like this:
public enum Foo {
BAR (0),
BAZ (1),
FII (10);
private final int index;
Foo(int index) {
this.index = index;
}
public int index() {
return index;
}
}
You'd use it like this:
public static void main(String[] args) {
for (Foo f : Foo.values()) {
System.out.printf("%s has index %d%n", f, f.index());
}
}
The thing to realise is that enum is just a shortcut for creating a class, so you can add whatever attributes and methods you want to the class.
If you don't want to define any methods on your enum you could change the scope of the member variables and make them public, but that's not what they do in the example on the Sun website.
If you have a contiguous range of values, and all you need is the integer value, you can just declare the enum minimally:
public enum NUMBERZ {
ZERO, ONE, TWO
}
and then obtain the int value as follows:
int numberOne = NUMBERZ.ONE.ordinal();
However, if you need a discontiguous range (as in your example, where you jump from 1 to 10) then you will need to write your own enum constructor which sets your own member variable, and provide a get method for that variable, as described in the other answers here.
It is:
enum Foo
{
Bar(0),
Baz(1),
Fii(10);
private int index;
private Foo(int index) {
this.index = index;
}
}
Note that to get the value of the enum from the index, Foo.valueOf(1) (*), would not work. You need do code it yourself:
public Foo getFooFromIndex(int index) {
switch (index) {
case 0:
return Foo.Bar;
case 1:
return Foo.Baz;
case 10:
return Foo.Fii;
default:
throw new RuntimeException("Unknown index:" + index);
}
}
(*): Enum.valueOf() return the enum from a String. As such, you can get the value Bar with Foo.valueOf('Bar')
Sounds like you want something like this:
public enum Foo {
Bar(0),
Baz(1),
Fii(10);
private int number;
public Foo(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
}
For starters, Sun's Java Enum Tutorial would be a great place to learn more.
public enum Foo {
Bar(0),
Baz(1),
Fii(10);
private final int someint;
Foo(int someint) {
this.someint = someint;
}
}
In Java enums are very similar to other classes but the the Java compiler knows to treat a little differently in various situations. So if you want data in them like you seem to you need to have an instance variable for the data and an appropriate constructor.