I need some help building a fluent interface (class wrapper) that allows me to create (and name) a 2D double array from curve sets in a database (in myWell). Ideally, a user could create a 2D double array when executing the following syntax (or something similar):
Double [,] CurveDoubleName = CreateIPmathCurves.CreateCurve(comboBox1.Text).CurveName("NPHIL").Make()
Where comboBox1 data comes from a WindowsForm called frmMain. Here's what I have so far:
namespace UserProgram
{
public class CreateIPmathCurve : frmMain, ICanNameCurve, ICanLocateCurve, ICanMakeCurve
{
private string _comboBoxName;
private string _CurveName;
private string _data;
// Private constructor - Only allow instantiated functions to create an IP math Curve
private CreateIPmathCurve()
{ }
// Instantiating functions
public static ICanNameCurve CreateCurve()
{
return new CreateIPmathCurve();
}
// Chaining functions
private CreateIPmathCurve(string data) { _data = data; } //private constructor prevents instantiation of your builder
public ICanLocateCurve SetCurveName(string CurveName)
{
_CurveName = CurveName;
return this; // this allows chaining.
}
public ICanMakeCurve SetComboBoxName(string comboBoxName)
{
_comboBoxName = comboBoxName;
return this; // this allows chaining.
}
// ending functions
public DataObject CreateCurveDoublArrayObj(string comboBoxName)
{
try
{
// User will need to populate comboBox.. example: comboBox1.text
char[] delimiter = { ':' };
Curve1inText = comboBoxName;
string[] crvIn1 = Curve1inText.Split(delimiter);
string CurveSet = crvIn1[0];
string Curve = crvIn1[1];
ICurveSet InCurveSet = myWell.FindCurveSet(CurveSet);
ICurve InMyCurve = myWell.FindCurve(Curve);
if (InMyCurve == null)
{
MessageBox.Show("You need to input a curve");
}
ILogReading[] In = InMyCurve.LogReadings.ToArray();
double[,] CurveDouble = new double[In.Length, 2];
int j = 0;
foreach (ILogReading reading in InMyCurve.LogReadings)
{
CurveDouble[j, 0] = reading.Depth;
CurveDouble[j, 1] = reading.Value;
j++;
}
return new DataObject(CurveDouble);
}
catch (Exception ex)
{
MessageBox.Show("Error building Double Array\n" + ex.Message + "\n" + ex.StackTrace);
return null;
}
}
public double[,] MakeCurve()
{
//this is where CurveName input ("NPHIL") should name the 2D double array listed from dataobject.
// I receive a "non-invocable member 'DataObject' cannot be used like a method" error....
_CurveName = DataObject(_comboBoxName);
return this;
// I also receive a "cannot implicity convert type UserProgram.CreateIPmathCurve' to 'double [*,*]"...
}
}
// using interfaces to enforce Fluent Interface grammar -- can't make curve if you don't know the location of curve, etc...
public interface ICanNameCurve
{
ICanLocateCurve SetCurveName(string CurveName);
}
public interface ICanLocateCurve
{
ICanMakeCurve SetComboBoxName(string comboBoxName);
}
public interface ICanMakeCurve
{
DataObject CreateCurveDoublArrayObj(string comboBoxName);
}
}
Can you help me create a CurveName() function that would allow the user to name the dataobject? (I tried a getter-setter accessor, but I don't think I was doing it correctly or am lacking a strong conceptual understanding of how it all works)
Lastly, can you also help me create a Make() function that puts all of this together?
To build a fluent API, you need to find a way to aggregate all data until your call to Make.
A simple way is to write a Builder, which holds all data. This builder has setter methods for every configurable field.
The key point here is that each setter method returns the Builder object, allowing you to chain calls.
public class FluentCurveBuilder
{
private string _name;
private string _data;
private string _color;
private FluentCurveBuilder(string data) { _data = data; } // private constructor prevents instantiation of your builder
public FluentCurveBuilder SetName(string name)
{
_name = name;
return this; // this allows chaining.
}
public FluentCurveBuilder SetColor(string color)
{
_color = color;
return this; // this allows chaining.
}
public static FluentCurveBuilder CreateCurve(string data)
{
return new FluentCurveBuilder(data);
}
public Curve Make()
{
// Creation logic goes here
}
}
You now can use the builder to configure your curve.
var curve = FluentCurveBuilder.CreateCurve("Data")
.SetName("Test")
.Make();
We have a static CreateCurve method, which returns a new builder. All other methods should only store the data in an instance field and return this builder.
In the Make method, you now have access to all previous aggregated data and you can construct your Curve
I think I was over analyzing my problem - The simple solution would be to create a method that returns the 2D double array and then assign a name to the object when I invoke the function... so using this:
public double [,] CreateIPmathCurve(string comboBoxName)
{
string CurveInText = "";
char[] delimiter = { ':' };
CurveInText = comboBoxName;
string[] crvIn = CurveInText.Split(delimiter);
string CurveSet = crvIn[0];
string Curve = crvIn[1];
ICurveSet InCurveSet = myWell.FindCurveSet(CurveSet);
ICurve InMyCurve = myWell.FindCurve(Curve);
if (InMyCurve == null)
{
MessageBox.Show("You need to input a curve");
}
ILogReading[] In = InMyCurve.LogReadings.ToArray();
double[,] CurveDouble = new double[In.Length, 2];
int j = 0;
foreach (ILogReading reading in InMyCurve.LogReadings)
{
CurveDouble[j, 0] = reading.Depth;
CurveDouble[j, 1] = reading.Value;
j++;
}
return CurveDouble;
Allows me to create the array with this:
double[,] NPHIL = CreateIPmathCurve(comboBox1.Text);
Thanks to everyone who helped me in this endeavor!
Related
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.
I am declaring two private arrays in indexes and displaying the data in main. However, it is not displaying any one tell me how to display the data in the two private arrays in indexers?
class Program
{
static void Main(string[] args)
{
student sc = new student();
for (int i = 0; i < sc.mlength; i++)
{
Console.WriteLine(sc[i]);
}
Console.ReadLine();
//i am declaring two private arrays in indexes and displaying the data in main is not displaying any one tell me how to display the data in the two private arrays in indexers?
}
}
public class student
{
private int[] _marks = new int[] { 60, 68, 70 };
private string[] _names = new string[] { "suri", "kumar", "suresh" };
public int this[int i]
{
get
{
return _marks[i];
}
set
{
_marks[i] = value;
}
}
public string this[int i]
{
get
{
return _names[Convert.ToInt32(i)];
}
set
{
_names[Convert.ToInt32(i)] = value;
}
}
public int mlength
{
get
{
return _marks.Length;
}
}
public int nlenght
{
get
{
return _names.Length;
}
}
}
}
Indexers allow your class to be used just like an array. On the inside of a class, you manage a collection of values any way you want. These objects could be a finite set of class members, another array, or some complex data structure. Regardless of the internal implementation of the class, its data can be obtained consistently through the use of indexers. Here’s an example.
Example:
using System;
class IntIndexer
{
private string[] myData;
public IntIndexer(int size)
{
myData = new string[size];
for (int i=0; i < size; i++)
{
myData[i] = "empty";
}
}
public string this[int pos]
{
get
{
return myData[pos];
}
set
{
myData[pos] = value;
}
}
static void Main(string[] args)
{
int size = 10;
IntIndexer myInd = new IntIndexer(size);
myInd[9] = "Some Value";
myInd[3] = "Another Value";
myInd[5] = "Any Value";
Console.WriteLine("\nIndexer Output\n");
for (int i=0; i < size; i++)
{
Console.WriteLine("myInd[{0}]: {1}", i, myInd[i]);
}
}
}
The IntIndexer class has a string array named myData. This is a private array that external users can’t see. This array is initialized in the constructor, which accepts an int size parameter, instantiates the myData array, and then fills each element with the word “empty”.
The IntIndexer class has a string array named myData. This is a private array that external users can’t see. This array is initialized in the constructor, which accepts an int size parameter, instantiates the myData array, and then fills each element with the word “empty”.
The next class member is the Indexer, which is identified by the this keyword and square brackets, this[int pos]. It accepts a single position parameter, pos. As you may have already guessed, the implementation of an Indexer is the same as a Property. It has get and setaccessors that are used exactly like those in a Property. This indexer returns a string, as indicated by the string return value in the Indexer declaration.
The Main() method simply instantiates a new IntIndexer object, adds some values, and prints the results. Here’s the output:
Indexer Output
myInd[0]: empty
myInd[1]: empty
myInd[2]: empty
myInd[3]: Another Value
myInd[4]: empty
myInd[5]: Any Value
myInd[6]: empty
myInd[7]: empty
myInd[8]: empty
myInd[9]: Some Value
I am relatively new to C# (WinForms), and had a question regarding combo boxes. I have a combo box of Reviewer objects (it is a custom class with an overridden ToString method) and am currently attempting to go through all the checked items and use them to generate a setup file.
Here is how the combo box is populated (populated on form load). Parameters is just a collection of linked lists and parsing code.
for (int i = 0; i < parameters.GetUsers().Count; i++)
{
UserList.Items.Add(parameters.GetUsersArray()[i], parameters.GetUsersArray()[i].isSelected());
}
Here is how I am trying to read it. setup is a StringBuilder. The problem is that GetID is not defined. Does the add function above cast the Reviewer object to a Object object? It looks a little funny since it creates a file fed into a Perl script. A sample desired output line looks like this: inspector0 => "chg0306",
for (int i = 0; i < UserList.CheckedItems.Count; i++)
{
setup.AppendLine("inspector" + i.ToString() + " => \t \"" +
UserList.CheckedItems[i].GetID() + "\",");
}
Here is the users class: (Sample User is ID = aaa0000 name: Bob Joe)
public class Reviewer
{
private string name;
private string id;
private bool selected;
public Reviewer(string newName, string newID, bool newSelected)
{
name = newName;
id = newID;
selected = newSelected;
}
public string GetName()
{
return name;
}
public override string ToString()
{
//string retVal = new string(' ', id.Length + name.Length + 1);
string retVal = id + '\t' + name;
return retVal;
}
public string GetID()
{
return id;
}
public bool isSelected()
{
return selected;
}
}
For posterity, here is the Parameters class:
public class ParameterLists
{
public ParameterLists()
{
projects = new LinkedList<string>();
reviewers = new LinkedList<Reviewer>();
}
public enum FileContents {
PROJECT_LIST,
USERS_LIST,
}
public LinkedList<Reviewer> GetUsers()
{
return reviewers;
}
public LinkedList<string> GetProjects()
{
return projects;
}
public Reviewer[] GetUsersArray()
{
Reviewer[] userArray = new Reviewer[reviewers.Count];
reviewers.CopyTo(userArray, 0);
return userArray;
}
public string[] GetProjectsArray()
{
String[] projectArray = new String[projects.Count];
projects.CopyTo(projectArray, 0);
return projectArray;
}
public void LoadParameters(string fileName)
{
//Reads the parameters from the input file.
}
private void CreateDefaultFile(string fileName)
{
// Create the file from the defaultfile , if it exists.
// Otherwise create a blank default file.
}
private LinkedList <string> projects;
private LinkedList <Reviewer> reviewers;
}
I am probably missing something simple, coming from embedded C++. Any help would be appreciated.
You have to cast that object:
((Reviewer)UserList.CheckedItems[i]).GetID()
Hello I'm trying to retrun array type named ZverejnenyUcetType but the issue is that this array might contain two types : StandartniUcetType and NestandardniUcetType.
So the issue is when I try to return the array like this:
string[] dic_vstup = new string[] { (line) };
RozhraniWSDL.InformaceOPlatciType[] dic_vystup;
RozhraniWSDL.rozhraniCRPDPH srv = new RozhraniWSDL.rozhraniCRPDPH();
StatusType status = srv.getStatusNespolehlivyPlatce(dic_vstup, out dic_vystup);
string abc = status.bezVypisuUctu.ToString(); // If it is already a string, then ToString not needed
for (int i = 0; i < dic_vystup.Length; i++)
{
RozhraniWSDL.InformaceOPlatciType info = dic_vystup[i];
for (int x = 0; x <= 3; x++)
{
file2.WriteLine((((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).cislo) + "-"
+ (((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).cislo) + "/"
+ (((RozhraniWSDL.StandardniUcetType)(info.zverejneneUcty[x].Item)).kodBanky));
}}
I get following exception: unable to cast object of type RozhraniWSDL.NestandardniUcetType to type RozhraniWSDL.StandardniUcetType.
NestandardniUcetType contains only one item - cislo
StandartníUcetType have 3 items- predcislo, cislo, kod banky
Here is an image of the array:
I thought that the solution might be to determinate which of the result are of type StandartniUcetType and which are NestandardniUcetType.
I would like to ask if this is possible to do?
I found this solution more common.
Thank you for your time.
If the array has two different types, you could add an if statement, like this:
if (info.zverejneneUcty[x].Item is RozhraniWSDL.StandardniUcetType) {
...
} else {
...
}
A slightly better approach would be to cast using the as operator, like this:
RozhraniWSDL.StandardniUcetType std = info.zverejneneUcty[x].Item as RozhraniWSDL.StandardniUcetType;
if (std != null) {
...
}
RozhraniWSDL.NestandardniUcetType nstd = info.zverejneneUcty[x].Item as RozhraniWSDL.NestandardniUcetType;
if (nstd != null) {
...
}
Finally, a very good approach would be writing two separate methods for the two types, and using dynamic to perform a dispatch. To do that, define two functions, like this:
static void WriteToFile(RozhraniWSDL.StandardniUcetType std, StreamWriter file) {
...
}
static void WriteToFile(RozhraniWSDL.NestandardniUcetType nstd, StreamWriter file) {
...
}
Now change your loop as follows:
for (int x = 0; x <= 3; x++) {
dynamic item = info.zverejneneUcty[x].Item;
WriteToFile(item, file2); // <<== Magic
}
Using the OfType extension method over the array will filter for the type you need
foreach (var item in info.zverejneneUcty.OfType<RozhraniWSDL.StandardniUcetType>())
{
file2.WriteLine(item.predcislo + "-" + item.cislo + "-" + item.kodBanky);
}
I'd redesign the types and remove the issue instead, through an abstract class, like this:
// I'm making up the inner types, adapt this to your code
public abstract class UcetType
{
public virtual object predcislo { get; set; }
public virtual object cislo { get; set; }
public virtual object kodBanky { get; set; }
public virtual void WriteToFile(StreamWriter file)
{
// build the string and write it to the file
// considering all properties
// this acts as "default" for this type and all derived ones
}
}
public class StandardniUcetType : UcetType
{
// This will use the abstract as-is
// with all 3 properties and the "default" WriteToFile() method
}
public class NestandardniUcetType : UcetType
{
/// <summary>
/// Attempting to use this will throw an exception
/// </summary>
public override object predcislo
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Attempting to use this will throw an exception
/// </summary>
public override object kodBanky
{
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
// change the way WriteToFile behaves
public override void WriteToFile(StreamWriter file)
{
// build the string and write it to the file
// only considering 'cislo' property
}
}
// Usage example, based on question
for (int i = 0; i < dic_vystup.Length; i++)
{
RozhraniWSDL.InformaceOPlatciType info = dic_vystup[i];
// I assume "3" is the expected length of the array ? Change the for like this:
for (int x = 0; x <= info.zverejneneUcty.Length; x++)
{
//Delegate to the WriteToFile() method the task to build and write the line!
info.zverejneneUcty[x].Item.WriteToFile(file2);
}
}
I see no benefit in a dynamic approach here. This is more readable and easy to expand in the future (need a new type ? just derive UcetType in a new class and override away).
I want to create an Matrix class for some calculations. At my research i was stumble over some performance discussions Array[,] vs Array[][] and they conclusion was always use Array[][] if you want it fast
When i'm trying to provide access to an value via [][] it seems like i miss something important because i cant create an property like this
public double this[int iRow][int iCol]
{
get { return matrix[iRow][iCol]; }
set { matrix[iRow][iCol] = value; }
}
my problem is the second [] because the following works well
public double this[int iRow,int iCol]
{
get { return matrix[iRow][iCol]; }
set { matrix[iRow][iCol] = value; }
}
So what do i need to add in this class to let it work with [][] ?
public class Matrix
{
private bool _isSquare;
private double[][] matrix;
public double this[int iRow,int iCol]
{
get { return matrix[iRow][iCol]; }
set { matrix[iRow][iCol] = value; }
}
}
You can't do this in one class.
var b = a[1][2];
is the same as
var temp = a[1];
var b = temp[2];
They are two separate indexing operations.
Your first indexer would need to return an instance of some class that also has an indexer.
Using Indexers (C#)
Not sure what you are trying to do but if your matrix was the following you could still do what you are looking for
public class M
{
public double[][] Matrix { get; private set; }
public M()
{
Matrix = new double[2][]{new double[2], new double[2]};
}
}
M n = new M();
n.Matrix[0][0] = 1.0;