When are defaults supplied in C# constructors? - c#

I am looking at this in C#:
namespace R3.Geometry
{
public class Tile
{
public Tile()
{
Isometry = new Isometry();
EdgeIncidences = new List<Tile>();
VertexIndicences = new List<Tile>();
}
public Tile( Polygon boundary, Polygon drawn, Geometry geometry )
: this()
{
Boundary = boundary;
Drawn = drawn;
Geometry = geometry;
VertexCircle = boundary.CircumCircle;
}
public Isometry Isometry { get; set; }
public Polygon Boundary { get; set; }
public Polygon Drawn { get; set; }
public CircleNE VertexCircle { get; set; }
public Geometry Geometry { get; set; }
public Tile Clone()
{
Tile newTile = new Tile();
newTile.Boundary = Boundary.Clone();
newTile.Drawn = Drawn.Clone();
newTile.VertexCircle = VertexCircle.Clone();
newTile.Geometry = Geometry;
return newTile;
}
// ...rest...
}
}
I am porting this C# to TypeScript (I am new to C#). From my reading/understanding so far, the get; set "properties" don't have any defaults. The : this() on the second constructor means that the second constructor calls into the first before it calls into itself, I'm pretty sure.
My question now is, are there any other defaults that get created or hidden/magical things that might happen? For example, in the Clone function, it calls Boundary.Clone(), but Boundary is never initialized if you just do let tile = new Tile(). Am I correct? Or what am I missing? Won't that cause an error?
If you call a constructor without any arguments, I feel like I might have read somewhere that it calls one of the constructors later in the chain with "default arguments" passed in. Is this the case somehow? That is, does Boundary, Draw, etc. always get created in this situation? What is the general flow if so?
If not, it seems there are two definitions of the Tile here, each with a different set of properties...
I also see this, with 2 constructors, both with : this, what does that mean?
public struct TilingConfig
{
public TilingConfig( int p, int q, int maxTiles ) : this()
{
SetupConfig( p, q, maxTiles );
}
public TilingConfig( int p, int q ) : this()
{
if( Geometry2D.GetGeometry( p, q ) != Geometry.Spherical )
throw new System.ArgumentException();
SetupConfig( p, q, PlatonicSolids.NumFacets( p, q ) );
}
// no more constructors.
}
For complex object classes/structs, if they are defined in parameters, do they get defaulted, like Polygon boundary in the Tile definition?

In your code public Tile() sets default values for the properties Isometry, EdgeIncidences, and VertexIndicences, and not for the properties Boundary, Drawn, VertexCircle and Geometry. these will not have any default values.
new Tile() calls the default constructor that is public Tile(). Inside the Clone method also you are calling the default constructor only.
using the default constructor will not give any error but you won't be able to use Boundary, Drawn, VertexCircle, and Geometry, as these are not as you have not assigned them any value. and if you try to access you may get null reference exception.
To answer your second question.
<YourConstructor> : this() means that the constructor calls the default constructor before executing its own code. if any default value or initialization should happen that will be done before this constructor code is executed. Its called the Constructor chaining.

You are on the right track -- but may need to analyze the flow carefully. The use of the : this() keyword here is called "constructor chaining" as discussed here.
As per that answer, it is a shorthand way to say:
Run the specified constructor before the current constructor
And here is another good answer discussing constructor chaining.
In addition, in your second example, you are dealing with a struct, while in your first example you are dealing with a class. This can get confusing as to how default values are handled with respect to the chaining. As per the MS article you linked, structs are value types versus classes which are reference types.

Related

VS 2022 17.1 wont build C# 10 struct (CS8983). 17.0.5 liked it. What happened?

I had this C# structure that was building in VS2022 literally up until last night when I upgraded from version 17.0.5 to 17.1
internal struct RoutineSettings
{
public bool Show { get; set; } = true;
public ShapeType PreferredShapeType { get; set; } = ShapeType.None;
}
(ShapeType is just an enum).
After the upgrade, I get this error:
error CS8983: A 'struct' with field initializers must include an explicitly declared constructor.
The explanation is straightforward enough. But since this code executed just fine before I am confused.
Is the compiler wrong?
Is it a true language requirement that the compiler was just failing to check for until now?
If the correct answer is #2, it begs the question why is this a requirement? Why is it needed? Because when I "fixed" it, the fix seemed pointless. I just added an empty default constructor:
internal struct RoutineSettings
{
public RoutineSettings() { }
public bool Show { get; set; } = true;
public ShapeType PreferredShapeType { get; set; } = ShapeType.None;
}
And now my code builds again. Why would I need this when it does nothing?
This really appears to have been a compiler bug in the previous version. Up to C# 9.0, structs where not allowed to have a default ctor, and it really was not generated, unlike for classes, where the default ctor was automatically generated when no constructor was defined. This allows to create value types without calling code (by just nullifying the memory). So apparently, they wanted to make this change explicit, because it really makes a difference in the code generated, whether the default constructor exists or not. Do note that in your example, the default constructor is not empty, because any field initializers are implicitly added to the constructor code. So in C# 10, when the constructor is declared, it is generated, otherwise it is left away from the generated IL.
Also note that there are a bunch of pitfalls when using this feature. The default ctor is still not executed when allocating an array of the struct:
[Fact]
public void StructCtorIsExecuted()
{
var r = new RoutineSettingsWithDefaultCtor();
Assert.Equal(10, r.PreferredShapeType);
RoutineSettingsWithDefaultCtor[] array = new RoutineSettingsWithDefaultCtor[10];
Assert.Equal(0, array[0].PreferredShapeType); // <-- When allocating an array, the default ctor is NOT executed
}
internal struct RoutineSettingsWithDefaultCtor
{
public RoutineSettingsWithDefaultCtor()
{
PreferredShapeType = 10;
}
public bool Show { get; set; } = true;
public int PreferredShapeType { get; set; } = 2;
}
}
some more problems are described here: https://davidshergilashvili.space/2021/09/05/c-10-struct-type-can-define-default-constructor/
That's not a bug, but rather a new design choice for C#:
https://github.com/dotnet/sdk/issues/23971
Solution:
Define a public parameter-less constructor and it will solve the issue.
For example, before:
public struct Abc
{
public int Num1 = 5;
}
After:
public struct Abc
{
public int Num1 = 5;
public Abc() {} // <--- Parameter-less default constructor
}

How to access the property of List <T> subclasses?

i've a Method which gets a List where T : Item.
How do i access the property from the Subclasses of Item?
private void CreateShopItem<T>(Transform itemTemplate, Transform shopScrollView, List<T> shopItemList)
where T : Item {
shopItemList.Name //this works
shopItemList.power //this is a property from the class cooling and i cant access it
}
Ive 4 subclasses from the base class Item but i can only access the properties from the Class Item
Item Class:
public class Item
{
public int Id;
public string Name;
public double Cost;
public Sprite Sprite;
public bool IsPlaced;
public Vector3 Position;
public Item()
{
Id = 0;
Name = "Default";
Cost = 0;
Sprite = null;
IsPlaced = false;
Position = Vector3.zero;
}
public Item(int id, string name, double cost, Sprite sprite, bool isPlaced, Vector3 position)
{
this.Id = id;
this.Name = name;
this.Cost = cost;
this.Sprite = sprite;
this.IsPlaced = isPlaced;
this.Position = position;
}
}
Sub Class Cooling:
public class Cooling : Item
{
public float power;
public float temp;
public Cooling(int id, string name, double cost, Sprite sprite, bool isPlaced, Vector3 position,
float power, float temp)
{
base.Id = id;
base.Name = name;
base.Cost = cost;
base.Sprite = sprite;
base.IsPlaced = isPlaced;
base.Position = position;
this.power = power;
this.temp = temp;
}
}
What would be a way to access the property of all subclasses from the Base Class?
Normally if a method needs to access a field/property this field would be included in the type that it accepts. While you can cast the item into a derived type, if you have to do it why accept the base type in the first place?
The problem is that if you use ifs or case when you add a new type you need to remember to come back to this piece of code and update it.
BTW. Use properties, not fields. It is the standard way:
public class Item
{
public int Id { get };
What you're asking the code to do doesn't make logical sense. When you use a generic type:
public class Foo<T>
{
public T Value { get; set; }
public void MyMethod()
{
// example code here
}
}
You are saying that you're going to be using a type (T) but you're not really sure yet which type you'll be using. The type will be specified at a later stage. The only assumption made by the compiler is that your T will derive from object.
This is okay, but that also means that you can't actually use this T with any more precision than you can use object. In the above example, you could call this.Value.ToString() because T is definitely an object (and object has the ToString() method), but you cannot call this.Value.Power because T is not known to be of the type Cooling (or a subtype).
You are able to influence what the compiler knows about the specific type that T will be. You've already done so by specifying that T will definitely be some sort of Item (i.e. class or subclass)
public class Foo<T> where T : Item
{
public T Value { get; set; }
public void MyMethod()
{
// example code here
}
}
Because the expectation is now that T is not just an object but also an Item, the compiler allows you to handle your T type with every known property/method of the Item type. You could access things like:
this.Value.Name
this.Value.Cost
this.Value.Sprite
Because these are properties of the Item class which you can definitely expect to see on any subclass of Item, you are allowed to access them when dealing with a T where T : Item generic type parameter.
You're trying to access a specific type's property (Cooling), without having told the compiler that your generic type is definitely going to be a (sub) class of Cooling.
That directly contradicts the core premise of using a generic type, i.e. treating a range of possible types using the same (generic) code. If that generic code were to only work with one specific type (i.e. Cooling), then there'd be no point in trying to make CreateShopItem work for any type that is not Cooling or one of its subtypes.
You need to go back to the drawing board with what it is that you want.
If I can assume that it is correct that CreateShopItem should work for any Item class, then you should inherently be able to write code that is able to handle any Item object without needing to know the specific concrete class being used.
I am very intentionally ignoring upcasting here because it's a bad approach that tries to cover for a bad design. Generic type upcasting is rarely a good idea. It violates OCP (in all but exceedingly rare examples), and would not be a good idea in this particular scenario anyway.
First of all the example that you show for the this one works and this one doesn't should be wrong because the reference that you are using is a List (List for your example) and the both of them will not work unless you get the element that you want to change from that list (with a loop or maybe with LINQ First() etc)
Secondly, If you want to access a field from a subclass while you have a base class object. You need to cast it to that subclass. For example:
class Item{
...
public int Id;
public string Name;
public double Cost;
}
class Cooling : Item {
...
public float power;
}
//Example method to call
private void CreateShopItem<T>(Transform itemTemplate, Transform shopScrollView, List<T> shopItemList)
where T : Item {
var firstItem = shopItemList().First(); // taking the first element just for example
firstItem.Name = "foo"; // this is fine
var coolingItem = (Cooling) firstItem;
coolingItem.power = 1000; // now this is also fine
}
This will fix your current case but I do not recommend to do it because as the subclasses increase this can turn into a big mess of casting disaster between classes.
I recommend to check out boxing/unboxing topic on C# for future use and best practices.

How can I add a default constructor and have it call another constructor and use the default values?

I have this code:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
When I try and use it then it's telling me I am missing a default constructor. How can I add one of these and still make the code use the default values for iconBackgroundColor and IconSource? I thought that adding in those defaults with the = Const. would make it work but it seems like it doesn't think my constructor is a default (with no params).
You just have to add another empty overload and call the required constructor with defaults. See below:
public class NewFrame
{
public NewFrame() : this(Const.Car, Const.Red){
}
public NewFrame(string iconSource,
string iconColor)
{
...
}
}
By having two optional parameters, you don't actually create 4 different constructor declarations under the hood (one with both parameters, one with the first parameter, one with the second parameter, and one with neither). There is still only one constructor, with two parameters. It's just that C# recognises that the parameters are optional, and has syntactic sugar to let you omit them when you call the constructor.
However, if you use reflection to create an instance of your class (probably whatever the thing that requires a default constructor is doing), and you attempt to invoke the parameterless constructor, it won't find one, because there is no syntactic sugar in reflection.
Here is an example:
class MainClass
{
public static void Main(string[] args)
{
Type t = typeof(MainClass);
object o = Activator.CreateInstance(t, 1);
Console.WriteLine(o);
}
public MainClass(int a = 10)
{
}
}
If you use typeof(MainClass).GetConstructors(), it will tell you that there is only one.
To actually declare a default constructor, you can do:
public class NewFrame
{
public NewFrame(string iconSource = Const.Car,
string iconColor = Const.Red)
{
...
}
public NewFrame() : this(Const.Car, Const.Red) { }
}
For what it's worth, when I do something like this, I take the route that #VyacheslavBenedichuk's answer is showing.
I'm not sure what your complaint is. This code compiles for me:
public class TestConstructor
{
public TestConstructor(string what = Const.Car, string color = Const.Red)
{
}
public static void Test()
{
var tc = new TestConstructor();
}
public class Const
{
public const string Car = "car";
public const string Red = "red";
}
}
What do your definitions of Const.Car and Const.Red look like? Where are you seeing the error?
But, if you use something that requires a default constructor, then this will not work. For example, this will fail at runtime:
var tc2 = Activator.CreateInstance(typeof(TestConstructor));
Please, when you are reporting an error, describe it exactly - in particular say whether it's a runtime or a compile-time error, the exact wording of the error, and the context in which the error occurs. In this case (the call to CreateInstance) will result in a System.MissingMethodException: 'No parameterless constructor defined for this object.'
In this case, you need to follow #VyacheslavBenedichuk's advice

OOP : Using Properties and Constructor

I am following c# complete reference. Following is the example that demonstrates Constructor and inheritance ,
class TwoDShape {
double pri_width;
double pri_height;
// Properties for Width and Height.
public double Width {
get { return pri_width; }
set { pri_width = value < 0 ? -value : value; }
}
public double Height {
get { return pri_height; }
set { pri_height = value < 0 ? -value : value; }
}
class Triangle : TwoDShape {
string Style;
// Constructor.
public Triangle(string s, double w, double h) {
Width = w;
Height = h;
Style = s;
}
Now in Program.cs inside Main() i have
static void Main() {
Triangle t1 = new Triangle("isosceles", 4.0, 4.0);
Triangle t2 = new Triangle("right", 8.0, 12.0);
}
My question is that when we are using properties and can initialize our fields using them why we use constructor and then inside this Constructor fields are initialized.
Which is better approach use construct / properties or this approach. Please also explain this approach as i am unable to get this logic (both constructor and properties for initialization)
Constructors should be used for classes that requires that certain variables (properties) are set for the class to be in a correct state. If you are using just properties, there is no guarantee that those properties are initialized as you get no compile errors and it's easy for the dev to forget to initialize them.
For instance, imagine that you have a class that do work in a database. If you define it like this:
public class UserRepository
{
public DbConnection Connection { get; set; }
public User GetUser(string id)
{
//...
}
}
.. the following code would compile fine:
var repos = new UserRepository();
var user = repos.GetUser("22");
.. but when you run it you'll get an exception.
If you instead use a constructor you won't be able to use the class unless you pass a database connection.
public class UserRepository
{
public UserRepository(DbConnection connection)
{
if (connection == null) throw new ArgumentNullException("connection");
Connection = connection;
}
public DbConnection Connection { get; private set; }
public User GetUser(string id)
{
//...
}
}
//Now forced to init the class correctly
var repos = new UserRepository(dbConnection);
var user = repos.GetUser("22");
Another aspect of this is code maintenance. When you initially write code you usually have full control over what it contains and how you should initialize the classes. Hence everything is working well. But when you come back to the project in a couple of months you'll probably forgot a lot. If you are using constructors then you can be sure that all classes you create have been initialized properly.
In simple terms using the constructor abstracts the work that is being done, placing it in a black box of sorts.
Setting the values on the properties gives the user more freedom at the risk that they may do something the developer of the class did not expect.
It all boils down to how much freedom you are willing to give those that use your class.
The constructor shoud set all the fields that are mandatory for the object. So you should implement a constructor that create a consistent instance.
Once the instance is created you can use properties to change the object state, but this could be dangerous because these changes can cause an incorrect state for your instance.
I always prefer to implement my classes as immutable types, so you set state in the constructor and only provide "getters" to access fields value.

Anonymous classes, temporary data, and collections of anonymous classes

I'm new to anonymous classes, and today I think I ran into the first case where I felt like I could really use them. I'm writing a method that would benefit from storing temporary data inside of a class, and since that class doesn't have any meaning outside of that method, using an anonymous class sure made sense to me (at least at the time it did).
After starting on the coding, it sure seemed like I was going to have to make some concessions. I like to put assign things like calculations to temporary variables, so that during debugging I can verify bits of calculations at a time in logical chunks. Then I want to assign something simpler to the final value. This value would be in the anonymous class.
The problem is that in order to implement my code with anonymous classes concisely, I'd like to use LINQ. The problem here is that I don't think you can do such temporary calculations inside of the statement. or can you?
Here is a contrived example of what I want to do:
namespace AnonymousClassTest
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
ObservableCollection<RectanglePoints> Points { get; set; }
public class RectanglePoints
{
public Point UL { get; set; }
public Point UR { get; set; }
public Point LL { get; set; }
public Point LR { get; set; }
}
public class DontWantThis
{
public double Width { get; set; }
public double Height { get; set; }
}
private Dictionary<string,string> properties = new Dictionary<string,string>();
private Dictionary<string,double> scaling_factors = new Dictionary<string,double>();
private void Sample()
{
// not possible to do temp variables, so need to have
// longer, more unreadable assignments
var widths_and_heights = from rp in Points
select new
{
Width = (rp.UR.X - rp.UL.X) * scaling_factors[properties["dummy"]],
Height = (rp.LL.Y - rp.UL.Y) * scaling_factors[properties["yummy"]]
};
// or do it in a for loop -- but then you have to use a concrete
// class to deal with the Width and Height storage
List<DontWantThis> other_widths_and_heights = new List<DontWantThis>();
foreach( RectanglePoints rp in Points) {
double base_width = rp.UR.X - rp.UL.X;
double width_scaling_factor = scaling_factors[properties["dummy"]];
double base_height = rp.LL.Y - rp.UL.Y;
double height_scaling_factor = scaling_factors[properties["yummy"]];
other_widths_and_heights.Add( new DontWantThis
{
Width=base_width * width_scaling_factor,
Height=base_height * height_scaling_factor
});
}
// now we want to use the anonymous class, or concrete class, in the same function
foreach( var wah in widths_and_heights)
Console.WriteLine( String.Format( "{0} {1}", wah.Width, wah.Height));
foreach( DontWantThis dwt in other_widths_and_heights)
Console.WriteLine( String.Format( "{0} {1}", dwt.Width, dwt.Height));
}
public Window1()
{
InitializeComponent();
Points = new ObservableCollection<RectanglePoints>();
Random rand = new Random();
for( int i=0; i<10; i++) {
Points.Add( new RectanglePoints { UL=new Point { X=rand.Next(), Y=rand.Next() },
UR=new Point { X=rand.Next(), Y=rand.Next() },
LL=new Point { X=rand.Next(), Y=rand.Next() },
LR=new Point { X=rand.Next(), Y=rand.Next() }
} );
}
Sample();
}
}
}
NOTE: don't try to run this unless you actually add the keys to the Dictionary :)
The creation of the anonymous class in LINQ is awesome, but forces me to do the calculation in one line. Imagine that the calc is way longer than what I've shown. But it is similar in that I will do some Dictionary lookups to get specific values. Debugging could be painful.
The usage of a concrete class gets around this problem of using temporary variables, but then I can't do everything concisely. Yes, I realize that I'm being a little contradictory in saying that I'm looking for conciseness, while asking to be able to save temp variables in my LINQ statement.
I was starting to try to create an anonymous class when looping over Points, but soon realized that I had no way to store it! You can't use a List because that just loses the entire anonymity of the class.
Can anyone suggest a way to achieve what I'm looking for? Or some middle ground? I've read a few other questions here on StackOverflow, but none of them are exactly the same as mine.
Assuming I understand you correctly, the problem is that you have to set all the properties in a single expression. That's definitely the case with anonymous types.
However, you don't have to do it all inline in that expression. I would suggest that if your properties are based on complex expressions, you break those expressions out into helper methods:
var complex = new {
First = ComputeFirstValue(x, y),
Second = ComputeSecondValue(a, b)
...
};
This has the additional potential benefit that you can unit test each of the helper methods individually, if you're a fan of white-box testing (I am).
This isn't going to avoid there being in one big anonymous type initializer expression, but it means the work will be broken up.
Anonymous classes are really intended to simplify stuff dealing with lambdas, not least LINQ. What you're trying to do sounds much more suited to a nested private class. That way, only your class really knows about your temp class. Trying to muck around with anonymous classes seems only to complicate your code.

Categories