Here is my code and it gives red squiggly line under the variable of the array declaration, stating,
Fixed size buffer fields may only be members of struct
float is a value type, so I don't quite understand this message.
What is the correct syntax to create public array of 13 elements (0 through 12; I ignore index 0)...
class clsUtility
{
public int UtilityId { get; set; }
public fixed float InterpolationFactorMonth[13]; // <-- HERE IS THE PROBLEM
}
If you want a fixed-sized array inline, that has to be declared within a struct, as per the compiler error. If you're actually happy with a reference to an array as normal, you need to differentiate between declaration and initialization. For example:
// Note: Utility isn't a great name either, but definitely lose the "cls" prefix.
class Utility
{
public int UtilityId { get; set; }
public float[] InterpolationFactorMonth { get; } = new float[13];
}
This declares a read-only property of type float[], and initializes it with a new array of 13 elements.
So first of all, it is not possible to use fixed in this case.
You could use public float[] InterpolationFactorMonth = new float[13];
To create an array of the size 13.
Related
I am trying to allocate an array of structures in C#. For example,
public struct Channel {
int ChannelId;
// other stuff goes here...
}
public struct FrameTraffic {
public int FrameId;
public int MaxChannels;
public Channel[] Channels;
public FrameTraffic(int dummyCS0568 = 0)
{
this.FrameId = 0;
MaxChannels = TableMgr.MaxChannels;
Channels = new Channel[TableMgr.MaxChannels];
}
}
But when I go to allocate an array of FrameTraffic structures, I see that Channels is null. This tells me that Channels is a reference rather than an array of structures. Am I correct? If so, then allocating the Channels array shouldn't embed the array into the structure, but simply satisfy the reference in the structure. I want the structures embedded. Is there a way to do this? Or am I incorrect in my assumptions?
Answering the later part of your question and disregarding any other problem. Yes you are correct, this will be a reference to an array. However, if you wanted to embed the array in the struct you can use a fixed sized buffer using the fixed and unsafe keywords. However that can only be known at design time, also it can only be of the following value types and not a user defined struct.
bool, byte, char, short, int, long, sbyte, ushort, uint, ulong, float, or double.
So in short, what you want to do is not possible, you may need to clarify why you need this or re-think your problem
You need to use the correct marshalling attribute, and it needs to have a fixed size, say 40
public struct FrameTraffic
{
public int FrameId;
public int MaxChannels;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
public Channel[] Channels;
}
I was able to replicate the null issue not sure if its the same with yours :
There are two things that i think is possibly causing this :
You are just initializing the array with size but not assigning any values
You might be initializing FrameTraffic with default construct instead of what you have defined (this caused the actual NPE for me)
Below is how you can adjust your code: (I have hardcoded values which is brought by TableMgr.MaxChannels since i dont have that)
class Program
{
static void Main()
{
FrameTraffic fT = new FrameTraffic(0);
foreach (var item in fT.Channels)
{
Console.WriteLine(item.ChannelId);
}
Console.Read();
}
}
public struct Channel
{
public int ChannelId; //missing public exposer if you really want to reassign
// other stuff goes here...
}
public struct FrameTraffic
{
public int FrameId;
public Channel[] Channels;
public FrameTraffic(int dummyCS0568 = 0)
{
this.FrameId = 0;
const int MaxChannels = 1;
//array requires size and its values assigned here
Channels = new Channel[MaxChannels]{ new Channel { ChannelId = 1 } };
}
}
Recently a compiler warning and (very useful) hint prompted me to write the code below.
I had no idea you could do this, but it is perfectly legal, and also convenient in that I can declare a managed struct with public properties similar to public fields of an unmanaged struct, and also initialize it with an object instead of having to pass all the fields as parameters.
What confuses me is that this appears to call the explicit parameterless constructor, which would of course be illegal for this struct.
What's going on here, and has this syntax always been supported?
internal struct IconEntry
{
public byte Width { get; set; }
public byte Height { get; set; }
public byte ColorCount { get; set; }
public byte Reserved { get; set; }
public short Planes { get; set; }
public short BitCount { get; set; }
public int BytesInRes { get; set; }
public int ImageOffset { get; set; }
public IconEntry(BinaryReader reader)
: this()
{
Width = reader.ReadByte();
Height = reader.ReadByte();
ColorCount = reader.ReadByte();
Reserved = reader.ReadByte();
Planes = reader.ReadInt16();
BitCount = reader.ReadInt16();
BytesInRes = reader.ReadInt32();
ImageOffset = reader.ReadInt32();
}
}
A struct always has a public parameterless constructor which can't be overriden: http://msdn.microsoft.com/en-us/library/aa288208%28v=vs.71%29.aspx
This means that a user still would be able to create an instance of this struct that is not initialized according to your logic but with default values for all properties:
var s = new IconEntry();
All structs have a parameterless constructor - it's just implicit (e.g. it always exists with a default routine - one that sets all values to 0) - you just can't have an explicit one (e.g. one that you define yourself in code).
Is there any reason you're exposing properties rather than fields for your struct? If the semantics of your data type imply that
The entire state of an instance will be fully defined by the values exposed by some public members, such that two instances for whom all those report or contain identical values will be considered identical.
Instances of the struct with any combination of values for the aforementioned members may be created easily, given the desired values in question.
that sounds like a perfect fit for a PODS (Plain Old Data Struct). Exposed fields are more efficient and less quirky than struct properties. Given that all struct types always expose all fields for mutation or capture by struct assignment, the encapsulation offered by struct properties is of extremely limited value.
The way you have your constructor written, your struct will have all fields set to all-bits-zero, and then be passed repeatedly to methods which will update one field at a time with the desired value. The fact that the struct is specified as initialized to all-bits-zero by the this will make the compiler happy, but using many individual properties to set up fields piecemeal is inefficient.
Incidentally, even better than a constructor in many cases would be a static method which simply takes your struct as a ref parameter. In many cases, using a constructor with a struct will result in an unnecessary copy operation which could be avoided by using a static method with a ref parameter.
Since structs are value types, it's data members should be initialized if you are explicitly invoke the constructor. And mention "this()" to intimate compiler to complete the assignment of auto implemented properties if anything you mentioned.
struct Student
{
string _sname;
public int ID
{
get; set;
}
internal Student(string sname):this()
{
_sname = sname;
}
internal void PrintDetails()
{
Console.WriteLine("ID : {0} Name: {1}", ID, _sname);
}
}
Main method:
class Program
{
static void Main()
{
Student st = new Student("John")
{
ID=101
};
st.PrintDetails();
}
}
Output:
ID : 101 Name: John
If you are not mention "this()", compiler forcefully ask you to complete the full assignment of ID property.
If you are not explicitly invoke the constructor, compiler implicitly set default values for the struct data members.
I'm new to programming and I have the following problem.
I have a class with with an Array. However, I only know what size the array will have at a later point.
public class MyData
{
public double[] rad;
public void Integrate(int h_start, int h_stop, double dla_tar)
{
rad = new double[Math.Abs(h_stop - h_start)];
...fill up the rad array
}
--work with rad here--
}
How can I get the function Integrate to create the rad array in the MyData class. Like that it always stays null. This is probably a very dumb question...
The key is to call Integrate before using rad. As long as you don't use rad in any way until you initialize it, you will be fine.
Any field in a C# class automatically starts out as the default value for that type, which is 0 for a numeric type (int, uint, long, etc.), false for a bool, and null for any reference type, including arrays. The canonical way to solve this problem is to initialize the data from the constructor. So you could do something like
public class MyData
{
public double[] rad
{
get;
private set;
}
public MyData(int start, int stop, double tar)
{
rad = new double[Math.Abs(start - stop)];
// More code here
}
// No need for an integrate method now - the work is done in the constructor
}
This way, it's impossible to use rad before it's initialized.
If you find that moving the initialization code to the constructor doesn't make sense, you probably need to refactor into two classes so that each class has one job.
Here is a struct I am trying to write:
public struct AttackTraits
{
public AttackTraits(double probability, int damage, float distance)
{
Probability = probability;
Distance = distance;
Damage = damage;
}
private double probability;
public double Probability
{
get
{
return probability;
}
set
{
if (value > 1 || value < 0)
{
throw new ArgumentOutOfRangeException("Probability values must be in the range [0, 1]");
}
probability = value;
}
}
public int Damage { get; set; }
public float Distance { get; set; }
}
This results in the following compilation errors:
The 'this' object cannot be used
before all of its fields are assigned
to
Field 'AttackTraits.probability' must
be fully assigned before control is
returned to the caller
Backing field for automatically
implemented property
'AttackTraits.Damage' must be fully
assigned before control is returned to
the caller. Consider calling the
default constructor from a constructor
initializer.
Backing field for automatically
implemented property
'AttackTraits.Distance' must be fully
assigned before control is returned to
the caller. Consider calling the
default constructor from a constructor
initializer.
What am I doing wrong?
If you see this error on a struct that has an automatic property, just call the parameterless contructor from your parameterized one by doing : this() example below:
struct MyStruct
{
public int SomeProp { get; set; }
public MyStruct(int someVal) : this()
{
this.SomeProp = someVal;
}
}
By calling :this() from your constructor declaration you let the base ValueType class initialize all the backing fields for the automatic properties. We cannot do it manually on our constructor because we don't have access to the backing field of an automatic property.
ValueType is the base class of all structs.
try to access probability field not accessor. In this case auto-props should work as well.
There is no way for a struct to have parameterless constructor so consider change it to class instead.
Best practise is to use structs only if they are 16 bytes or less and are immutable. So if you are going to change object fields after creating, consider refactoring it to class.
Also, you can change constructor definition to:
construct(params) : this()
this will remove error as well
You're setting the probability field through the Probability property, but the compiler doesn't know that the property sets the field... so you need to explicitly initialize the probability field itself
public AttackTraits(double probability, int damage, float distance)
{
this.probability = 0;
Distance = distance;
Damage = damage;
}
Change the line Probability = probability to this.probability = probability
In the future pick a different naming convention for fields as you do for parameters. For example, prefix all fields with an underscore, so you can simply call this:
_probability = probability;
and see easily what's happening.
try to change struct to class for AttackTraits
public class AttackTraits
{
.........
{
In a attempt to put some more oop in a program i am looking to make a private instance variable in one class (object) accesable to a class.
private byte [][] J;
All those code refers to this jagged array with this.
Now in the other class i putted all the for loops along with the consolewritlines to display the wanted results. Basicly it says "the name J does not exist in the current context"
But how exactly do i make this J accesable?
I have tried with get and set but i keep getting 'cannot convert to byte to byte[][]'
Also what kind of cyntax would i need with get and set?
Something along like this? Or would i need several more steps? :
public Byte JArray
get { return J; } //can converrt to byte here
set { J = value; } //cannnot convert to byte here
Kind regards
If you want to expose a variable via a property, the type of the property has to be the same as the type of the variable (or compatible):
public byte[][] JArray
{
get { return J; }
set { J = value; }
}
However, you probably don't really need the setter - unless you actually want callers to be able to change J to refer to a different jagged array. Just with a getter they can still change values within the array, but they can't change the variable itself.
Even with this though, callers could still change the contents of the "outer" array, changing a whole "column" at a time:
foo.JArray[10] = new byte[10];
An alternative is to add an indexer to your class:
public byte this[int x, int y]
{
get { return J[x][y]; }
set { J[x][y] = value; }
}
This will only let callers access the actual elements, hiding the fact that it's backed by an array.
Exposing an array directly is generally a bad idea - indeed, leading minds consider arrays to be somewhat harmful.
If I understand the situation correctly, the problem is that your types are mismatched.
Since the variable's type is byte[][] (i.e., an array of arrays of bytes) your property's return type needs to be byte[][]. Currently it's Byte.
That's because the types of your private variable and the public property are not the same. Try this:
public byte[][] JArray
{
get { return J; }
set { J = value; }
}
Or even shorter using automatic properties:
public byte[][] JArray { get; set; }
if J is of type byte[][], the associate property should also be of type byte[][].