How shouldi avoid the CS0120 error in my code? [duplicate] - c#

This question already has answers here:
CS0120: An object reference is required for the nonstatic field, method, or property 'foo'
(9 answers)
Closed 5 years ago.
First i'll give you a run around my code,
I have a class that stores some data :
public class Balta
{
public int x;
public int y;
public int raza;
public int cantApa;
public int id;
public int intersect;
public Balta(int xs, int ys, int r, int cApa, int ids, int intersctt)
{
x = xs;
y = ys;
raza = r;
cantApa = cApa;
id = ids;
intersect = intersctt;
}
}
Secondly I have a class that makes a list of that data and stores it acordingly,also i intend to do some operations with that data once i get rid of this pesky error.
public class Baltile
{
public int n;
List<Balta> balti = new List<Balta>();
public void populate(Balta balta)
{
int unitId = balta.id;
if (balti.Any(Balta => Balta.id == balta.id))
{
int pos = balti.FindIndex(Balta => Balta.id == balta.id);
balti[pos] = balta;
}
else if (balti.Any(Balta => Balta.cantApa == -1) && !balti.Any(Balta => Balta.id == unitId))
{
int pos = balti.FindIndex(Balta => Balta.cantApa == -1);
balti[pos] = balta;
}
else //daca nu inseamna ca aduaugi balta la lista
{
balti.Add(balta);
}
}
}
And main looks something like this
static void Main(string[] args)
{
Baltile balti = new Baltile();
while (true)
{
"data input block"
for (int i = 0; i < unitCount; i++)
{
"more data input"
if (i>2)
{
Balta balta = new Balta(x, y, radius, extra, unitId, 0);
Baltile.populate(balta);//the CS0120 error is here
}
}
}
}
So CS0120 tells me this An object reference is required for the non-static field, method, or property.This means main is static so i cant call a non static method if i understood right ? Declaring everything static will give even more errors.
How should i go around this ? I cant seem to figure out how to make my code work ?

With
Baltile.populate(balta);
and Baltile being a class name, this would require populate() to be a static method.
As per MSDN, the full error message is
Compiler Error CS0120
An object reference is required for the nonstatic field, method, or
property 'member'
This tells you to use an object instead of a class. And it seems you already have an object called balti that serves this purpose. So use
balti.populate(balta);
instead. Now you call the populate() method on an instance (an object) instead of the class.

Related

the "This" keyword front of constructor parentheses - C# [duplicate]

This question already has answers here:
Calling constructor from other constructor in same class
(3 answers)
Closed last month.
I know about "This" keyword and what is it working. but what is this using for?
public ReactiveProperty() : this(default(T))
{
}
I have seen this in UniRx Project. I just don't know the "This" keyword front of constructor.
I googled it but there is nothing to catch.
does anyone know?
This syntax is used to call another constructor defined in the class. Example from the docs:
class Coords
{
public Coords() : this(0, 0) // calls Coords(int x, int y) with x = 0 and y = 0
{ }
public Coords(int x, int y)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
public override string ToString() => $"({X},{Y})";
}
var p1 = new Coords();
Console.WriteLine($"Coords #1 at {p1}");
// Output: Coords #1 at (0,0)
var p2 = new Coords(5, 3);
Console.WriteLine($"Coords #2 at {p2}");
// Output: Coords #2 at (5,3)

Passing array by value in c#

As far as I understand, the default type or argument passing in c# is by value. Therefore no statement is required. But when I try the run following code, my A matrix in Main is being modified by the operations done to dMatrixU in the Factorize() method of class Decomposition. I'm sure the problem is in the constructor of the Decomposition when I just assing A to dMatrixU, the reference of A is being assigned instead of the values. Therefore my question on how to avoid this, all I have found is how to pass the arguments by reference. Again, as I understand no modifier is needed for passing the argument by value. Where am I wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using LinearEquations;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
double[,] A = new double[,]
{ { 1, 1, 1 } ,
{ 4, 3, -1 } ,
{ 3, 5, 3 } };
double[] B = new double[] {1,6,4};
Decomposition lu = new Decomposition(A,B);
lu.Factorize();
PrintMatrix(A,"A:");
PrintVector(B,"B:");
PrintMatrix(lu.L,"L:");
PrintMatrix(lu.U,"U:");
PrintVector(lu.D,"D:");
}
public static void PrintMatrix(double[,] M, String Title = "Matrix: ")
{
Console.WriteLine(Title);
for(int i = 0; i<M.GetLength(0); i++)
{
for(int j = 0; j<M.GetLength(1);j++)
{
Console.Write(M[i,j]+"\t");
}
Console.Write("\n");
}
Console.Write("\n");
}
public static void PrintVector(double[] V, String Title = "Vector: ",bool AsRow = true)
{
String str = (AsRow)? "\t" : "\n";
Console.WriteLine(Title);
for(int i = 0; i<V.GetLength(0); i++)
{
Console.Write(V[i]+str);
}
Console.WriteLine("\n");
}
}
}
namespace LinearEquations
{
public class Decomposition
{
// Fields
private double[,] dMatrixA; // Parameter in A*X=B
private double[] dVectorB; // Parameter in A*X=B
private double[] dVectorX; // Result wanted in A*X=B
private double[,] dMatrixU; // A splits into L and U
private double[,] dMatrixL; // L is used to calculate D in L*D=B
private double [] dVectorD; // D is used to calculate X in U*X=D
// Properties
public double[,] A
{
get { return dMatrixA; }
set { dMatrixA = value; }
}
public double[] B
{
get { return dVectorB; }
set { dVectorB = value; }
}
public double[] X
{
get { return dVectorX; }
set { dVectorX = value; }
}
public double[,] L
{
get { return dMatrixL; }
set { dMatrixL = value; }
}
public double[,] U
{
get { return dMatrixU; }
set { dMatrixU = value; }
}
public double[] D
{
get { return dVectorD; }
set { dVectorD = value; }
}
// Constructor
public Decomposition(double[,] A, double[] B)
{
dMatrixA = A;
dVectorB = B;
dVectorX = new double[B.Length];
dMatrixU = A;
dMatrixL = new double[A.GetLength(0),A.GetLength(1)];
dVectorD = new double[B.Length];
}
// Split A into L and U
public void Factorize()
{
// Iterate per each row
for(int i = 0; i<dMatrixU.GetLength(0); i++)
{
// For all the rows make element i equals 0
for(int j = i+1; j<dMatrixU.GetLength(0);j++)
{
// Factor that assures substraction makes 0
dMatrixL[1,1] = dMatrixU[j,i] / dMatrixU[i,i];
// Iterate per each column
for(int k = 0; k<dMatrixU.GetLength(1);k++)
{
dMatrixU[j,k] = dMatrixU[j,k] - dMatrixU[i,k]*dMatrixL[1,1];
}
}
}
}
}
}
As far is i understand, the default type or argument passing in c# is by value.
Unfortunately it is a bit more complicated and also has some execptions:
Reference types like Decomposition you hand in by making a copy of the reference. Unfortunately that means both still reference the same instance in memory. So despite a copy operation, it is call-by-Reference.
With value types like Int or double and their aliases, usually a copy is made. I do not know of any case where it does not, but I was wrong on those things before. So they are call by value.
Finally String and a few other reference types are inmutable by design. That has the advantage that they behave kinda like value types in this area. You hand in a Reference, but the instance itself can not be changed. The code can only create a new instance in memory with a different value. So despite handing over literal references, it kinda works like call by value.
Your specific case
Arrays are very explicitly Reference types. Handing them into a function without side effects, requires proper cloning. If it is a array of reference types, the cloning must be deep.
In your case you have arrays of value types. If you want to avoid call-by-reference side effects, you those arrays must be cloned. However as double is a value type, this cloning can be shallow. No need for a deep clone.
Unlike Java there is not a dedicated Clone() Method. And I am not sure why exactly. However you can often use one Collection to initialize another through the constructor. Or they even have a function like Array.Copy(), as TheBatman pointed out.

How to check if an object with the same Id already exist inside a list of objects before adding it?

I'm learning C# at the moment and I'm trying to make a list of objects. Before adding an object to the list, I want to check if an object with the same id already exist inside the list. (I can't have 2 "merchandise" objects with same "id".)
Here's the code (just realized I named every variable, class and method in French. hope it's still understandable):
using System;
using System.Collections.Generic;
public class Program
{
class Marchandise
{
private int _id; // attribute I need to check in every object before adding
public int Id{get; set;}
private double _poids;
public double Poids{get; set;}
private double _volume;
public double Volume{get; set;}
public Marchandise( int id, double poids, double volume)
{
this._id = id;
this._poids = poids;
this._volume = volume;
}
}
class Transport
{
public double _distance;
List<Marchandise> _listeMarchandise = new List<Marchandise>();
public void Ajout(Marchandise marchandise)
{
// add function with duplicate check for ID
}
}
public static void Main()
{
Marchandise m1 = new Marchandise(20,27.6,89.2); //test code
Marchandise m2 = new Marchandise(20,10.2,5.1);
Transport t1 = new Transport();
t1.Ajout(m1);
t1.Ajout(m2);
}
}
Dictionary would be better choice over List, as Dictionary ensures that keys are unique:
class Transport
{
public double _distance;
Dictionary<int, Marchandise> _listeMarchandise = new Dictionary<int, Marchandise>();
public void Ajout(Marchandise merchandise)
{
_listeMarchandise[merchandise.Id] = merchandise;
}
}
You can use the LINQ method Any() to check if there is an object which mets a specific condition. In your case you check if there is an object which have such an Id. You can use it like this:
class Transport
{
public double _distance;
List<Marchandise> _listeMarchandise = new List<Marchandise>();
public void Ajout(Marchandise marchandise)
{
if (_listeMarchandise.Any(it => it.Id == marchandise.Id)) {
// it already exists, do something about it.
}
// add fonction with duplicate check for ID
}
}

Returning a reference of a struct instead of a copy on C# 3.0?

I have this code:
using System;
using System.Collections.Generic;
using UnityEngine;
public interface HaveId
{
int id { get; }
}
public struct BusinessData : HaveId
{
// business type data
public int graphic_asset_id;
public string name;
public int id { get; set; }
}
public class LookupHelper<T> where T: HaveId
{
private T[] _list;
public T[] list
{
get { return _list; }
set { _list = value; _mapToDictionary(); }
}
private Dictionary<int, int> idxById = new Dictionary<int, int>();
public LookupHelper(){}
private void _mapToDictionary()
{
if(idxById.Count > 0) idxById = new Dictionary<int, int>();
for(var z =0 ; z < list.Length; ++z)
{
idxById[list[z].id] = z;
}
}
public bool IsIdExists(int id)
{
return idxById.ContainsKey(id);
}
public T ById(int id) // is this a reference?
{
var idx = idxById[id];
if (idx >= list.Length) throw new Exception(
String.Format("Invalid Index: {0} >= {1} on {2}",idx.ToString(),list.Length.ToString(), typeof(T).Name)
);
return list[idx];
}
}
And the test code:
LookupHelper<BusinessData> bd = new LookupHelper<BusinessData>();
bd.list = new BusinessData[]
{
new BusinessData{id = 1, name = "test"},
new BusinessData{id = 2, name = "test2"},
};
bd.ById(1).name = "foo";
This give an error: "Cannot modify struct member when accessed struct is not classified as a variable"
How can I change the value of first BusinessData and keep the array still allocated on a contiguous memory (array of struct, needed for cache locality)?
This should be a simple matter of splitting it up into a few lines. Extract the object to get a copy, modify the copy, then overwrite it in the array:
BusinessData bsd = bd.ById(1);
bsd.name = "foo";
bd.SetById(1, bsd);
Of course, you'll need to write that SetById method to reinsert things into the array:
public void SetById(int id, T obj)
{
Int32 idx = idxById[id];
list[idx] = obj;
}
As you know C# borrowed something’s from C and Java. But not everything.
In C, you can create a place for struct on the stack or the heap. On the heap, I can then pass a pointer around and change the content. Very powerful.
But C# emphasizes ease of memory management via garbage collection. To make it easy, C# has the concept of boxing value types into System.Object. Additional details, can be found on Microsoft C# Programming Guide on Boxing and unboxing.
So when you access the value type in your list, you have to explicitly unbox the value. Therefore it’s a copy of the item in the list. You can do what #Nyerguds suggested.
But to make life easy, why not turn your BusinessData into a class?

declare variable as a field of the class [duplicate]

This question already has answers here:
Use a variable from another method in C#
(2 answers)
Closed 5 years ago.
Using C#
This is a basic question I'm sure. I'm getting the error.. "The name '_stocks' does not exist in the current context". I know this is because I declared the _stocks dictionary within the Initialize method. This makes the _stocks variable a local variable and only accessible within the Initialize method. I need to declare the _stocks variable as a field of the class (so it can be accessed by any method of the class). The other method as you will see below is OnBarUpdate(). How do I go about declaring the _stocks variable as a field of the class?
public class MAcrossLong : Strategy
{
//Variables
private int variable1 = 0
private int variable2 = 0
public struct StockEntry
{
public string Name { get; set; }
public PeriodType Period { get; set; }
public int Value { get; set; }
public int Count { get; set; }
}
protected override void Initialize()
{
Dictionary<string, StockEntry> _stocks = new Dictionary<string, StockEntry>();
_stocks.Add("ABC", new StockEntry { Name = "ABC", Period = PeriodType.Minute, Value = 5, Count = 0 } );
}
protected override void OnBarUpdate()
{
//_stocks dictionary is used within the code in this method. error is occurring within this method
}
}
**Added Portion....
I should probably just post the code within OnBarUpdate() because I'm now getting other errors...
The best overloaded method match for 'System.Collections.Generic.Dictionary.this[string]' has some invalid arguments
Argument '1': cannot convert from 'int' to 'string'
Operator '<' cannot be applied to operands of type 'NinjaTrader.Strategy.MAcrossLong.StockEntry' and 'int'
protected override void OnBarUpdate()
{ //for loop to iterate each instrument through
for (int series = 0; series < 5; series++)
if (BarsInProgress == series)
{
var singleStockCount = _stocks[series];
bool enterTrade = false;
if (singleStockCount < 1)
{
enterTrade = true;
}
else
{
enterTrade = BarsSinceEntry(series, "", 0) > 2;
}
if (enterTrade)
{ // Condition for Long Entry here
EnterLong(200);
{
if(_stocks.ContainsKey(series))
{
_stocks[series]++;
}
}
}
}
}
You need to declare _stocks in a class level scope. Since you have declared it within the Initialize method its visibility becomes local to that method. So you should declare it along with variable1 and variable2 like
private int variable1 = 0;
private int variable2 = 0;
private Dictionary<string, StockEntry> _stocks;
You might need to look into the Access modifiers and Variable and Method Scopes for a better understanding
The same way you declared variable1 and variable2....
public class MAcrossLong : Strategy
{
private int variable1 = 0;
private int variable2 = 0;
private Dictionary<string, StockEntry> _stocks;
protected override void Initialize()
{
_stocks.Add("ABC", new StockEntry { Name = "ABC", Period = PeriodType.Minute, Value = 5, Count = 0 } );
}
protected override void OnBarUpdate()
{
_stocks["ABC"].Name = "new name"; // Or some other code with _stocks
}
}
To fix the error inside the OnBarUpdate() that you recently added, you need to switch to a foreach loop and use a KeyValuePair<string, StockEntry> iterator. You can read more on them here, here, and here.
It should look something like this:
foreach(KeyValuePair<string, StockEntry> stock in _stocks)
{
string ticker = stock.Key;
StockEntry stockEntry = stock.Value;
// Or some other actions with stock
}

Categories

Resources