cast child class to another with base class - c#

I need to have some Length units that can convert them together
Length class as parent
Meter, Centimeter, Millimeter as Childs:
public abstract class Length
{
}
public class Meter: Length
{
public Meter(double val)
{
Value = val;
}
public double Value { get; set; }
public static explicit operator Centimeter(Meter m)
{
return new Centimeter(m.Value * 100);
}
public static explicit operator Millimeter(Meter m)
{
return new Millimeter(m.Value * 1000);
}
}
public class Centimeter: Length
{
public Centimeter(double val)
{
Value = val;
}
public double Value { get; set; }
public static explicit operator Meter(Centimeter cm)
{
return new Meter(cm.Value / 100);
}
public static explicit operator Millimeter(Centimeter cm)
{
return new Millimeter(cm.Value * 10);
}
}
public class Millimeter: Length
{
public Millimeter(double val)
{
Value = val;
}
public double Value { get; set; }
public static explicit operator Meter(Millimeter mm)
{
return new Meter(mm.Value / 1000);
}
public static explicit operator Centimeter(Millimeter mm)
{
return new Centimeter(mm.Value / 10);
}
}
I can cast Meter to Millimeter with this code:
Meter m = new Meter(3)
Millimeter mm = (Millimeter)m; //it's ok. result is 3000
But I need to have base class type to hold my variable:
Length l;
if (true)
l = new Meter(3);
else
l = new Centimeter(20)
Millimeter m = (Millimeter)l;//runtime Error
I get runtime error :
System.InvalidCastException: 'Unable to cast object of type 'Meter' to type 'Millimeter'.'

This might be in the direction you are hoping to get. Having one class be able to overall handle either conversion of millimeter, centimeter or meter. In this class sample, I am having the class store the value to the lowest granularity of millimeter. Now, that said, you might even want the millimeters level down to an integer vs a double, unless you want to allow for fraction of millimeter, but your choice.
public class MyLength
{
// always store at the lowest possible scale here
private double _millsValue;
private MyLength( double alwaysMillimeters)
{
_millsValue = alwaysMillimeters;
}
// have constructor return a MyLength based on whatever type wanted with
// the STATIC method name make sure it builds out to proper millimeter reference
public static MyLength Millimeter( double val)
{ return new MyLength(val); }
// 10 millimeters to 1 centimeter, so an incoming 5 centimeters = 50 millimeters
public static MyLength Centimeter( double val)
{ return new MyLength(val * 10); }
// similarly, 1000 millimeters to 1 meter, so 2 meters = 2000 millimeters
public static MyLength Meter (double val)
{ return new MyLength(val * 1000); }
// Now, expose public getter / setter that are bound to the
// underlying _millsValue and divide back out by 10 or 1000 respectively
public double Millimeters
{
get { return _millsValue; }
set { _millsValue = value; }
}
public double Centimeters
{
get { return _millsValue / 10; }
set { _millsValue = value * 10; }
}
public double Meters
{
get { return _millsValue / 1000; }
set { _millsValue = value * 1000; }
}
}
And to show how all applied and getting values out regardless of basis created and handling the conversion for you via getters / setters
public class LengthTest
{
public LengthTest()
{
var L = MyLength.Millimeter(1000);
var mm = L.Millimeters; // returns 1000
var cm = L.Centimeters; // returns 100
var m = L.Meters; // returns 1
var C = MyLength.Centimeter(3);
mm = C.Millimeters; // returns 30
cm = C.Centimeters; // returns 3
m = C.Meters; // returns .03
var M = MyLength.Meter(2);
mm = M.Millimeters; // returns 2000
cm = M.Centimeters; // returns 200
m = M.Meters; // returns 2
// can also SET values based on respective named getter/setter
var someVal = MyLength.Centimeter(0);
someVal.Centimeters = 250;
mm = someVal.Millimeters; // returns 2500
cm = someVal.Centimeters; // returns 250
m = someVal.Meters; // returns 2.5
someVal.Meters = .75;
mm = someVal.Millimeters; // returns 750
cm = someVal.Centimeters; // returns 75
m = someVal.Meters; // returns .75
someVal.Millimeters = 250;
mm = someVal.Millimeters; // returns 250
cm = someVal.Centimeters; // returns 25
m = someVal.Meters; // returns .25
}
}

Related

How to choose different elements within an array of objects in c#

I have an Invoice class and a main class. I have an array of objects within my main class and I want to multiply the quantity(7) by the price(57.88). How do you select different elements within an object array. I have shown my main and my invoice classes. I'm looking for an example on how I would go about this pertaining to what I have done with my code.
static void Main(string[] args)
{
var tools = new[]
{
new Invoice(83,"Electric Sander", 7, 57.88M),
new Invoice(24, "Power Saw", 18, 99.99M),
new Invoice(7, "Sledge Hammer", 11, 21.50M),
new Invoice(77, "Hammer", 76, 11.99M),
new Invoice(39, "Lawn Mower", 3, 79.50M),
new Invoice(68, "Screwdriver", 106, 6.99M),
new Invoice(56, "Jig Saw", 21, 11.00M),
new Invoice(3, "Wrench", 34, 7.50M)
};
Console.WriteLine("Original Array: ");
foreach (var tool in tools)
{
Console.WriteLine(tool);
}
var descriptionSort = from t in tools
orderby t.PartDescription
select t;
}
public class Invoice
{
// declare variables for Invoice object
private int quantityValue;
private decimal priceValue;
// auto-implemented property PartNumber
public int PartNumber { get; set; }
// auto-implemented property PartDescription
public string PartDescription { get; set; }
// four-argument constructor
public Invoice(int part, string description,
int count, decimal pricePerItem)
{
PartNumber = part;
PartDescription = description;
Quantity = count;
Price = pricePerItem;
}
// property for quantityValue; ensures value is positive
public int Quantity
{
get
{
return quantityValue;
}
set
{
if (value > 0) // determine whether quantity is positive
{
quantityValue = value; // valid quantity assigned
}
}
}
// property for pricePerItemValue; ensures value is positive
public decimal Price
{
get
{
return priceValue;
}
set
{
if (value >= 0M) // determine whether price is non-negative
{
priceValue = value; // valid price assigned
}
}
}
// return string containing the fields in the Invoice in a nice format;
// left justify each field, and give large enough spaces so
// all the columns line up
public override string ToString() =>
$"{PartNumber,-5} {PartDescription,-20} {Quantity,-5} {Price,6:C}";
}
You could always just add a getter to your Invoice class
public decimal TotalPrice
{
get
{
return Price * Quantity;
}
}
tools[0].TotalPrice to get the first element in your array
You already "select different objects" here:
foreach (var tool in tools)
{
Console.WriteLine(tool);
}
You could add to this, and even keep a total:
double total = 0;
foreach (var tool in tools)
{
Console.WriteLine($"{tool.Quantity} of {tool.Name} (costing {tool.Price} each) totals {tool.Quantity * tool.Price}");
total += (tool.Quatity * tool.Price);
}
Console.WriteLine("Invoice total " + total);
You can also access arrays etc by index, typical examples being:
for(int x = 0; x < tools.Length; x++)
Console.WriteLine(tools[x].Price);
for(int x = tools.Length-1; x >= 0; x--)
Console.WriteLine(tools[x].Price);
This is a common requirement to do that they have a shortcut - you type forTABTABorforr`TABTAB VS will insert skeletons of these for you

Can I use the keyword "in" to separate parameters in a method declaration somehow?

I would like to create a method that uses the keyword in instead of a comma to separate parameters in a method declaration; something similar to the foreach(a in b) method.
Example
Class Structure
public class Length
{
public double Inches;
public double Feet;
public double Yards;
public enum Unit { Inch, Foot, Yard }
Dictionary<Unit, double> inchFactor = new Dictionary<Unit, double>()
{
{ Unit.Inch, 1 },
{ Unit.Foot, 12 },
{ Unit.Yard, 36 }
};
public Length(double value, Unit unit)
{
this.Inches = value * inchFactor[unit];
this.Feet = this.Inches / inchFactor[Unit.Foot];
this.Yards = this.Inches / inchFactor[Unit.Yard];
}
}
Method Definition in Class
// I'd like to know how to use "in" like this ↓
public List<Length> MultiplesOf(Length divisor in Length dividend)
{
double inchEnumeration = divisor.Inches;
List<Length> multiples = new List<Length>();
while (inchEnumeration <= dividend.Inches)
{
multiples.Add(new Length(inchEnumeration, Length.Unit.Inch));
inchEnumeration += divisor.Inches;
}
return multiples;
}
Ideal Implementation
private void DrawRuler()
{
Length eighthInch = new Length(0.125, Length.Unit.Inch);
Length oneFoot = new Length(1, Length.Unit.Foot);
// Awesome.
List<Length> tickGroup = Length.MultiplesOf(eighthInch in oneFoot);
double inchPixels = 10;
foreach (Length tick in tickGroup)
{
// Draw ruler.
}
}
I've looked into creating new keywords, but it looks like C# does not support defining keywords.
As has been mentioned in the comments, you cannot define custom keywords in C# (unless you extend the compiler, which is an advanced task). However, if your goal is to clarify the meaning of the two arguments, then I would suggest using named arguments instead:
// Define the method as usual:
public List<Length> MultiplesOf(Length divisor, Length dividend)
{
// ...
}
// Then call it like so, explicitly showing what is the divisor and the dividend:
List<Length> tickGroup = Length.MultiplesOf(divisor: eighthInch, dividend: oneFoot);
While you can't redefine an existing keyword, there is other way to accomplish what you in a slightly different way using Fluent Interface :
public class Length
{
// ...
public static IFluentSyntaxProvider MultiplesOf(Length divisor)
{
return new FluentSyntaxProvider(divisor);
}
public interface IFluentSyntaxProvider
{
List<Length> In(Length dividend);
}
private class FluentSyntaxProvider : IFluentSyntaxProvider
{
private Length divisor;
public FluentSyntaxProvider(Length divisor)
{
this.divisor = divisor;
}
public List<Length> In(Length dividend)
{
double inchEnumeration = divisor.Inches;
List<Length> multiples = new List<Length>();
while (inchEnumeration <= dividend.Inches)
{
multiples.Add(new Length(inchEnumeration, Length.Unit.Inch));
inchEnumeration += divisor.Inches;
}
return multiples;
}
}
}
Example of usage :
// Awesome.
List<Length> tickGroup = Length.MultiplesOf(eighthInch).In(oneFoot);

How to sort list by many criterias

I need sort list of nodes with fields: distance and frequency. I need that node with min distance and max frequency have been placed at the top.
list.OrderByDedcending(frequency).ThenBy(distance) - not that case.
I want get average between OrderBy(distance) and orderByDescending(frequency)
Example:
№ Distance frequency
1 6 15
2 4 10
3 5 3
I don't know how explain more clearly
I guess you want to order by weight,just like
class Demo
{
public int Distance { get; set; }
public int Frequency { get; set; }
public override string ToString()
{
return string.Format("Distance:{0} Frequency:{1}", this.Distance, this.Frequency);
}
}
List<Demo> list = new List<Demo>
{
new Demo{ Distance=3, Frequency=15},
new Demo{ Distance=4, Frequency=17},
new Demo{ Distance=5, Frequency=3},
};
int[] weight = { 30, 70 };
var tmp = list.OrderByDescending(x => x.Distance * 0.3 + x.Frequency * 0.7);//there just a guess
foreach(var q in tmp)
{
Console.WriteLine(q);
}
You can use the List.sort() with a comparer that you create to fit your needs :)
public class ObjectBasedComparer : IComparer<ObjectType>
{
public int Compare(ObjectType a, ObjectType b)
{
//Your logic here...
}
}

After calculation of arrays, it shows that cannot implicitly convert type 'decimal' , even though I used decimal data

I cannot create object that contains arrays of property inside object
After I fixed the last problem from the link above, I am faced with a new one, and I tried search one posted but I still struck with it.
In the last line I want to use Result(object) to view and I don't know how to pass it.
The problem is in the last line (return), it said
Cannot implicitly convert type 'decimal'
thank you all :)
namespace finance3.Models
{
public class Expected_and_Risk
{
public void Initialize(int size)
{
Prop = new decimal[size];
AxB = new decimal[size];
Forecast = new decimal[size];
PowAxB = new decimal[size];
Name = new string[size];
}
public decimal[] Prop { get; set; }
public decimal[] Forecast { get; set; }
public string[] Name { get; set; }
public decimal[] AxB { get; set; }
public decimal[] PowAxB { get; set; }
public decimal ExpectValue(Expected_and_Risk abc)
{
int count = abc.Forecast.Count();
Expected_and_Risk Result = new Expected_and_Risk();
Result.Initialize(count);
for (int i = 0 ; i < count ; i++)
{
Result.Name[i] = abc.Name[i];
Result.Prop[i] = abc.Prop[i];
Result.Forecast[i] = abc.Forecast[i];
Result.AxB[i] = abc.Prop[i] * abc.Forecast[i];
decimal a = Result.AxB[i];
decimal sumAxB =+ a;
double temp = (double)(a * a) ;
Result.PowAxB[i] = (decimal)(temp);
}
// here is the problem
return (Result);
}
}
}
You're trying to return your custom object, rather than a decimal.
Change:
public decimal ExpectValue(Expected_and_Risk abc)
to this:
public Expected_and_Risk ExpectValue(Expected_and_Risk abc)
You could fix your compilation error by changing the method's signature:
public Expected_and_Risk ExpectValue(Expected_and_Risk abc) { //...
I have no idea if that makes any sense for your logic, however.
Alternatively if there's a way to convert an Expected_and_Risk object to a single numeric value, you could declare a conversion operator or an instance method to calculate that value, and return it instead:
return (decimal)Result;
or
return Result.DistillToDecimalValue();
Before you even read the rest of this answer, consider the following: Its improbable to return a class constructor as a another form without proper conversion. (Such as a ToDecimal() method, that you might want to create), so change:
public decimal ExpectValue(Expected_and_Risk abc)
to:
public Expected_and_Risk ExpectValue(Expected_and_Risk abc)
Here is my take on this problem:
when you place statement "return (Result);", i believe there are two possible problems.
1) You should have formatted the return statement like so:
return (decimal)Result;
2) You should have converted the object to a decimal, while checking that the result is a valid decimal (You must create a conversion method "ToString()"):
decimal retVal = 0;
if (!decimal.TryParse(Result.ToString(), out retVal)) throw new ArgumentException("Invalid Result"); //put whatever you want inplace of the argumentexception
return retVal;
Although i'm sure the solution at the top will work, if it doesnt just try the other two above.
As dbaseman explained a bit, you are returning a Expected_and_Rick class object, while your method return type is decimal.
And about the loop, you will always return only one Expected_and_Rick object, since you override it in a for loop. I would suggest you to create a List, where T will be Expected_and_Rick class.
public List<Expected_and_Risk> ExpectValue(Expected_and_Risk abc)
{
int count = abc.Forecast.Count();
List<Expected_and_Risk> list = new List<Expected_and_Risk>();
Result.Initialize(count);
for (int i = 0 ; i < count ; i++)
{
Expected_and_Risk Result = new Expected_and_Risk();
Result.Name[i] = abc.Name[i];
Result.Prop[i] = abc.Prop[i];
Result.Forecast[i] = abc.Forecast[i];
Result.AxB[i] = abc.Prop[i] * abc.Forecast[i];
decimal a = Result.AxB[i];
decimal sumAxB =+ a;
double temp = (double)(a * a) ;
Result.PowAxB[i] = (decimal)(temp);
list.Add(Result);
}
return list;
}
And on the other side you can have like:
Expected_and_Risk data = ....
List<Expected_and_Risk> list = ExpectValue(data);

Arrays and measurement unit conversion

using (read = new StreamReader("C:/Users/Sam Smith/Desktop/convert.txt"))
{
while (!read.EndOfStream)
{
lineFromFile = read.ReadLine();
units = lineFromFile.Split(',');
if (units.Contains(splitEntry[0]) && units.Contains(splitEntry[1]))
{
firstUnit = units[0];
secondUnit = units[1];
userConvertValue = Convert.ToDouble(splitEntry[2]);
fileConvertValue = Convert.ToDouble(units[2]);
result = fileConvertValue * userConvertValue;
}
if (units.Contains(splitEntry[0]) && units.Contains(splitEntry[1]))
{
firstUnit = units[1];
secondUnit = units[0];
userConvertValue = Convert.ToDouble(splitEntry[2]);
fileConvertValue = Convert.ToDouble(units[2]);
result = userConvertValue / fileConvertValue;
}
if (!units.Contains(splitEntry[0]) || !units.Contains(splitEntry[1]))
{
Console.WriteLine("Error, measurement unit not recognised.");
}
Above I have a text file that contains types of unit measurement (pounds, ounces, miles and such), the text from this file is split into a string array.
The user enters two measurement units in the following format to convert to two units:
unit,unit,amount
In the text file, the conversion amount for two units is every third split string, like so:
unit,unit,2.80
unit,unit,1.27 (etc)
Is there a way of grouping each set of units and their conversion amounts? For example, if the user tries to convert two particular units, the program knows which conversion value to use when calculating the final result.
Might be a little vague, but it's difficult to explain.
EDIT: The user does not interact with the file, the program simply pulls the data from the file, which is then split into strings (',') and stored in an array.
If I don't got you wrong, the following code should fulfill your requirements (it's very basic, no error handling etc.):
public enum Unit
{
Pound,
Kilo,
Kilometer,
Mile
}
public class UnitMapping
{
public UnitMapping(Unit source, Unit target, double factor)
{
SourceUnit = source;
TargetUnit = target;
Factor = factor;
}
public Unit SourceUnit { get; private set; }
public Unit TargetUnit { get; private set; }
public double Factor { get; private set; }
}
public class UnitCalculator
{
public const string FILE_INPUT = #"Kilo,Pound,0.45359237
Kilometer,Mile,1.609344";
private List<UnitMapping> mappings;
public UnitCalculator()
{
this.mappings = new List<UnitMapping>();
// parse the mappings
foreach (var line in FILE_INPUT.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
{
var fields = line.Split(',');
var source = (Unit)Enum.Parse(typeof(Unit), fields[0]);
var target = (Unit)Enum.Parse(typeof(Unit), fields[1]);
double factor = double.Parse(fields[2], CultureInfo.InvariantCulture);
this.mappings.Add(new UnitMapping(source, target, factor));
}
}
public double Convert(Unit source, Unit target, double value)
{
foreach (var mapping in this.mappings)
{
if (mapping.SourceUnit == source && mapping.TargetUnit == target)
{
return value * mapping.Factor;
}
else if (mapping.SourceUnit == target && mapping.TargetUnit == source)
{
return value * (1 / mapping.Factor);
}
}
throw new InvalidOperationException("No mapping could be found for this conversion.");
}
}
Invoke it like this:
static void Main(string[] args)
{
var calc = new UnitCalculator();
Console.WriteLine(calc.Convert(Unit.Mile, Unit.Kilometer, 1));
}
If you don't know the units, you can use strings as well.

Categories

Resources