In continuation to my previous question C# Confluent.Kafka SetValueDeserializer object deserialization, I have tried creating my custom deserializer to deserialize protobuf message but getting this error:
System.InvalidOperationException: 'Type is not expected, and no contract can be inferred: Ileco.Chimp.Proto.FinalValue'
on line:
return Serializer.Deserialize<T>(stream);
Here my consumer and deserializer:
class Worker
{
public static void Consumer(string brokerList, string connStr, string consumergroup, string topic, string cacertlocation)
{
var config = new ConsumerConfig
{
BootstrapServers = brokerList,
SecurityProtocol = SecurityProtocol.SaslSsl,
SocketTimeoutMs = 60000, //this corresponds to the Consumer config `request.timeout.ms`
SessionTimeoutMs = 30000,
SaslMechanism = SaslMechanism.Plain,
SaslUsername = "$ConnectionString",
SaslPassword = connStr,
SslCaLocation = cacertlocation,
GroupId = consumergroup,
AutoOffsetReset = AutoOffsetReset.Earliest,
BrokerVersionFallback = "1.0.0", //Event Hubs for Kafka Ecosystems supports Kafka v1.0+, a fallback to an older API will fail
//Debug = "security,broker,protocol" //Uncomment for librdkafka debugging information
};
using (var consumer = new ConsumerBuilder<string, FinalValue>(config)
.SetKeyDeserializer(Deserializers.Utf8)
.SetValueDeserializer(new MyCustomDeserializer<FinalValue>())
.SetErrorHandler((_, e) => Console.WriteLine($"Error: {e.Reason}"))
.Build())
{
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) => { e.Cancel = true; cts.Cancel(); };
consumer.Subscribe(topic);
Console.WriteLine("Consuming messages from topic: " + topic + ", broker(s): " + brokerList);
while (true)
{
try
{
var msg = consumer.Consume(cts.Token);
Console.WriteLine($"Received: '{msg.Message.Value}'");
//var bytes = Encoding.ASCII.GetBytes(msg.Message.Value);
//var fv = FromByteArray<ProtobufMsg>(bytes);
//var proto = ProtoDeserialize<ProtobufMsg>(bytes);
}
catch (ConsumeException e)
{
Console.WriteLine($"Consume error: {e.Error.Reason}");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
}
}
}
}
public class MyCustomDeserializer<T> : IDeserializer<T>
{
public T Deserialize(ReadOnlySpan<byte> data, bool isNull, Confluent.Kafka.SerializationContext context)
{
using (var stream = new MemoryStream(data.ToArray()))
{
return Serializer.Deserialize<T>(stream);
}
}
}
FinalValue.proto
syntax = "proto3";
package ileco.chimp.proto;
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
option java_package = "ileco.chimp.proto";
option java_outer_classname = "FinalValueProtos";
message FinalValue {
google.protobuf.Timestamp timestamp = 1;
uint32 inputId = 2;
google.protobuf.DoubleValue value = 3;
uint32 sourceId = 4;
string inputGuid = 5;
}
FinalValue.cs
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: proto/FinalValue.proto
#pragma warning disable 1591, 0612, 3021
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Ileco.Chimp.Proto {
/// <summary>Holder for reflection information generated from proto/FinalValue.proto</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class FinalValueReflection {
#region Descriptor
/// <summary>File descriptor for proto/FinalValue.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static FinalValueReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChZwcm90by9GaW5hbFZhbHVlLnByb3RvEhFpbGVjby5jaGltcC5wcm90bxof",
"Z29vZ2xlL3Byb3RvYnVmL3RpbWVzdGFtcC5wcm90bxoeZ29vZ2xlL3Byb3Rv",
"YnVmL3dyYXBwZXJzLnByb3RvIp4BCgpGaW5hbFZhbHVlEi0KCXRpbWVzdGFt",
"cBgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASDwoHaW5wdXRJ",
"ZBgCIAEoDRIrCgV2YWx1ZRgDIAEoCzIcLmdvb2dsZS5wcm90b2J1Zi5Eb3Vi",
"bGVWYWx1ZRIQCghzb3VyY2VJZBgEIAEoDRIRCglpbnB1dEd1aWQYBSABKAlC",
"JQoRaWxlY28uY2hpbXAucHJvdG9CEEZpbmFsVmFsdWVQcm90b3NiBnByb3Rv",
"Mw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Ileco.Chimp.Proto.FinalValue), global::Ileco.Chimp.Proto.FinalValue.Parser, new[]{ "Timestamp", "InputId", "Value", "SourceId", "InputGuid" }, null, null, null)
}));
}
#endregion
}
#region Messages
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class FinalValue : pb::IMessage<FinalValue> {
private static readonly pb::MessageParser<FinalValue> _parser = new pb::MessageParser<FinalValue>(() => new FinalValue());
public static pb::MessageParser<FinalValue> Parser { get { return _parser; } }
public static pbr::MessageDescriptor Descriptor {
get { return global::Ileco.Chimp.Proto.FinalValueReflection.Descriptor.MessageTypes[0]; }
}
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
public FinalValue() {
OnConstruction();
}
partial void OnConstruction();
public FinalValue(FinalValue other) : this() {
Timestamp = other.timestamp_ != null ? other.Timestamp.Clone() : null;
inputId_ = other.inputId_;
Value = other.Value;
sourceId_ = other.sourceId_;
inputGuid_ = other.inputGuid_;
}
public FinalValue Clone() {
return new FinalValue(this);
}
/// <summary>Field number for the "timestamp" field.</summary>
public const int TimestampFieldNumber = 1;
private global::Google.Protobuf.WellKnownTypes.Timestamp timestamp_;
public global::Google.Protobuf.WellKnownTypes.Timestamp Timestamp {
get { return timestamp_; }
set {
timestamp_ = value;
}
}
/// <summary>Field number for the "inputId" field.</summary>
public const int InputIdFieldNumber = 2;
private uint inputId_;
public uint InputId {
get { return inputId_; }
set {
inputId_ = value;
}
}
/// <summary>Field number for the "value" field.</summary>
public const int ValueFieldNumber = 3;
private static readonly pb::FieldCodec<double?> _single_value_codec = pb::FieldCodec.ForStructWrapper<double>(26);
private double? value_;
public double? Value {
get { return value_; }
set {
value_ = value;
}
}
/// <summary>Field number for the "sourceId" field.</summary>
public const int SourceIdFieldNumber = 4;
private uint sourceId_;
public uint SourceId {
get { return sourceId_; }
set {
sourceId_ = value;
}
}
/// <summary>Field number for the "inputGuid" field.</summary>
public const int InputGuidFieldNumber = 5;
private string inputGuid_ = "";
public string InputGuid {
get { return inputGuid_; }
set {
inputGuid_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
public override bool Equals(object other) {
return Equals(other as FinalValue);
}
public bool Equals(FinalValue other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!object.Equals(Timestamp, other.Timestamp)) return false;
if (InputId != other.InputId) return false;
if (Value != other.Value) return false;
if (SourceId != other.SourceId) return false;
if (InputGuid != other.InputGuid) return false;
return true;
}
public override int GetHashCode() {
int hash = 1;
if (timestamp_ != null) hash ^= Timestamp.GetHashCode();
if (InputId != 0) hash ^= InputId.GetHashCode();
if (value_ != null) hash ^= Value.GetHashCode();
if (SourceId != 0) hash ^= SourceId.GetHashCode();
if (InputGuid.Length != 0) hash ^= InputGuid.GetHashCode();
return hash;
}
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
public void WriteTo(pb::CodedOutputStream output) {
if (timestamp_ != null) {
output.WriteRawTag(10);
output.WriteMessage(Timestamp);
}
if (InputId != 0) {
output.WriteRawTag(16);
output.WriteUInt32(InputId);
}
if (value_ != null) {
_single_value_codec.WriteTagAndValue(output, Value);
}
if (SourceId != 0) {
output.WriteRawTag(32);
output.WriteUInt32(SourceId);
}
if (InputGuid.Length != 0) {
output.WriteRawTag(42);
output.WriteString(InputGuid);
}
}
public int CalculateSize() {
int size = 0;
if (timestamp_ != null) {
size += 1 + pb::CodedOutputStream.ComputeMessageSize(Timestamp);
}
if (InputId != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(InputId);
}
if (value_ != null) {
size += _single_value_codec.CalculateSizeWithTag(Value);
}
if (SourceId != 0) {
size += 1 + pb::CodedOutputStream.ComputeUInt32Size(SourceId);
}
if (InputGuid.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(InputGuid);
}
return size;
}
public void MergeFrom(FinalValue other) {
if (other == null) {
return;
}
if (other.timestamp_ != null) {
if (timestamp_ == null) {
timestamp_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
}
Timestamp.MergeFrom(other.Timestamp);
}
if (other.InputId != 0) {
InputId = other.InputId;
}
if (other.value_ != null) {
if (value_ == null || other.Value != 0D) {
Value = other.Value;
}
}
if (other.SourceId != 0) {
SourceId = other.SourceId;
}
if (other.InputGuid.Length != 0) {
InputGuid = other.InputGuid;
}
}
public void MergeFrom(pb::CodedInputStream input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
input.SkipLastField();
break;
case 10: {
if (timestamp_ == null) {
timestamp_ = new global::Google.Protobuf.WellKnownTypes.Timestamp();
}
input.ReadMessage(timestamp_);
break;
}
case 16: {
InputId = input.ReadUInt32();
break;
}
case 26: {
double? value = _single_value_codec.Read(input);
if (value_ == null || value != 0D) {
Value = value;
}
break;
}
case 32: {
SourceId = input.ReadUInt32();
break;
}
case 42: {
InputGuid = input.ReadString();
break;
}
}
}
}
}
#endregion
}
#endregion Designer generated code
As I noted yesterday, you appear to have used the Google .proto processing tools (protoc), but are using protobuf-net; if you want to use protobuf-net, similar command-line/IDE/build/etc tools exist that are compatible with the protobuf-net library, or you can use https://protogen.marcgravell.com/ for ad-hoc usage (to avoid having to install anything). Alternatively: continue using the Google schema tools, but use the Google library. Basically: they need to match.
The only minor gotcha here is that protobuf-net does not currently have explicit inbuilt support for DoubleValue; for reference: this can be considered as simply:
namespace Google.Protobuf.WellKnownTypes
{
[ProtoContract]
public sealed class DoubleValue
{
[ProtoMember(1)]
public double Value {get;set;}
}
}
I should probably find time to take all the types from wrappers.proto and allow them as double?, float?, long? etc - but it will need an additional marker, as Nullable<T> is already handled but with a different meaning (i.e. optional in .proto terms)
The float word I think is inappropriate but...
I try to make a custom slider control and seems to work fine but for some reason for some values the control crashes.
For example if I choose Maximum value = 1.112 the slider show maximum 1.111 and if I increase the value with numeric Up Down I get this error:
System Argument Out Of Range Exception H Result = 0x80131502
Message=Value of '1112' is not valid for 'Value'. 'Value' should be
between 'Minimum' and 'Maximum'.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace UserSliderControl
{
//set the default event for this user control
[DefaultEvent("ValueChanged")]
public partial class SliderControl : UserControl
{
//set the initial values
private int multiplier = 1;
private float minimum = 0f;
private float maximum = 100f;
private int decimalPlaces = 0;
private float _value = 0f;
private float resetvalue = 0f;
private int largeChange = 5;
private Image buttonResetImage = null;
private Color controlNameForeColor = SystemColors.WindowText;
//set the event handler for this user control = ValueChanged
public event EventHandler ValueChanged;
//set the properties for this user control
#region properties
public string ControlName
{
get { return labelControlName.Text; }
set
{
labelControlName.Text = value;
}
}
public Color ControlNameForeColor
{
get { return controlNameForeColor; }
set
{
controlNameForeColor = value;
labelControlName.ForeColor = controlNameForeColor;
}
}
public Image ButtonResetImage
{
get { return buttonResetImage; }
set
{
buttonResetImage = value;
btnReset.BackgroundImage = buttonResetImage;
btnReset.BackgroundImageLayout = ImageLayout.Zoom;
}
}
public float Value
{
get { return _value; }
set
{
_value = value;
if (_value > maximum) _value = maximum;
if (_value < minimum) _value = minimum;
NumericUpDown.Value = (decimal)_value;
}
}
public float ResetValue
{
get { return resetvalue; }
set
{
resetvalue = value;
if (resetvalue > maximum) resetvalue = maximum / 2;
if (resetvalue < minimum) resetvalue = minimum;
}
}
public float Maximum
{
get { return maximum; }
set
{
maximum = value;
if (maximum < minimum)
{
maximum = 2 * minimum;
}
TrackBar.Maximum = (int)(maximum * multiplier);
NumericUpDown.Maximum = (decimal)maximum;
}
}
public float Minimum
{
get { return minimum; }
set
{
minimum = value;
if (minimum > maximum)
{
minimum = 0;
}
TrackBar.Minimum = (int)minimum * multiplier;
NumericUpDown.Minimum = (int)minimum;
}
}
public int DecimalPlaces
{
get { return decimalPlaces; }
set
{
decimalPlaces = value;
if (decimalPlaces > 3)
{
decimalPlaces = 3;
}
multiplier = (int)Math.Pow(10, decimalPlaces);
NumericUpDown.DecimalPlaces = decimalPlaces;
NumericUpDown.Increment = 1m / multiplier;
}
}
public int LargeChange
{
get { return largeChange; }
set
{
largeChange = value;
TrackBar.LargeChange = largeChange;
}
}
#endregion
public SliderControl()
{
InitializeComponent();
}
private void TrackBar_Scroll(object sender, EventArgs e)
{
NumericUpDown.Value = (decimal)TrackBar.Value / multiplier;
Value = (float)TrackBar.Value / multiplier;
OnValueChanged();
}
private void NumericUpDown_ValueChanged(object sender, EventArgs e)
{
TrackBar.Value = (int)(NumericUpDown.Value * multiplier);
Value = (float)NumericUpDown.Value;
OnValueChanged();
}
private void btnReset_Click(object sender, EventArgs e)
{
NumericUpDown.Value = (decimal)ResetValue;
TrackBar.Focus();
OnValueChanged();
}
protected virtual void OnValueChanged()
{
ValueChanged?.Invoke(this, EventArgs.Empty);
}
}
}
I learn programming oriented object, and I want to do this code but I got those problems, I think I don't really know the concept of virtual.
View image 1
Code:
class Joueur
{
private string _nom;
private string _prenom;
private DateTime _dateDeNaissance;
private string _position;
private bool _reserve;
public string nom
{
get { return _nom; }
set { _nom = value; }
}
public string prenom
{
get { return _prenom; }
set { _prenom = value; }
}
public DateTime dateDeNaissance
{
get { return _dateDeNaissance; }
set { _dateDeNaissance = value; }
}
public string position
{
get { return _position; }
set { _position = value; }
}
public bool reserve
{
get { return _reserve; }
set { _reserve = value; }
}
public Joueur()
{
}
public Joueur(string nom, string prenom, DateTime dateDeNaissance, string position, bool reserve)
{
this.nom = nom;
this.prenom = prenom;
this.dateDeNaissance = dateDeNaissance;
this.position = position;
this.reserve = reserve;
}
public double virtual CalculerPrime(int joues, int gagnes)
{
double Prime;
if (reserve == false)
Prime = 10000 * (gagnes / joues);
else
Prime = ((10000 * (gagnes / joues)) / 2);
return Prime;
}
}
You need to do like this in your code:
public virtual double CalculerPrime(int joues, int gagnes)
{
double Prime;
if (reserve == false)
Prime = 10000 * (gagnes / joues);
else
Prime = ((10000 * (gagnes / joues)) / 2);
return Prime;
}
I am currently working on a BMI calculator for my C# class. My app asks the user for either their height in feet and inches and their weight in pounds or their height in centimeters and weight in kilograms. Their is a tab control that has buttons for Imperial mode or Metric mode.
If the "calculate" button in the imperial tab is clicked, I need to make sure that the heightFt, heightIn, and weightLbs text boxes have been filled out. Then I convert those to the metric units. If the calculate button in the metric tab is clicked, I need to make sure that the heightCm and weightKg text boxes have been filled out.
Once those are provided, I then convert the height and weight to BMI. If I use if(heightFt == null) I get the following error:
The result of the expression is always 'false' since a value of type 'double' is never equal to 'null' of type 'double?'
How do I fix this?
This is my MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace BMICalculator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private BMICalc _BMICalc;
public MainWindow()
{
_BMICalc = new BMICalc();
InitializeComponent();
}
private void calculateImperial_Click(object sender, RoutedEventArgs e)
{
_BMICalc.heightFt = Convert.ToDouble(heightFt.Text);
_BMICalc.heightIn = Convert.ToDouble(heightIn.Text);
_BMICalc.weightLbs = Convert.ToDouble(weightLbs.Text);
_BMICalc.doCalculation("Imperial");
if (_BMICalc.error == null)
{
MessageBox.Show("Your BMI is " + _BMICalc.bmi + " and you are " + _BMICalc.category, "Your BMI");
}
}
}
}
This is BMICalc.cs
using System;
using System.Windows;
using System.ComponentModel;
namespace BMICalculator
{
class BMICalc :INotifyPropertyChanged
{
public double _heightFt { get; set; }
public double _heightIn { get; set; }
public double _heightCm { get; set; }
public double _weightLbs { get; set; }
public double _weightKg { get; set; }
public double _bmi { get; set; }
public string _category { get; set; }
public string _error { get; set; }
public double heightFt
{
get { return heightFt; }
set
{
_heightFt = value;
OnPropertyChanged("heightFt");
}
}
public double heightIn
{
get { return _heightIn; }
set
{
_heightIn = value;
OnPropertyChanged("heightIn");
}
}
public double heightCm
{
get { return _heightCm; }
set
{
_heightCm = value;
OnPropertyChanged("heightCm");
}
}
public double weightLbs
{
get { return _weightLbs; }
set
{
_weightLbs = value;
OnPropertyChanged("weightLbs");
}
}
public double weightKg
{
get { return _weightKg; }
set
{
_weightKg = value;
OnPropertyChanged("weightKg");
}
}
public double bmi
{
get { return _bmi; }
set
{
_bmi = value;
OnPropertyChanged("bmi");
}
}
public string error
{
get { return _error; }
set
{
_error = value;
OnPropertyChanged("error");
}
}
public string category
{
get { return _category; }
set
{
_category = value;
OnPropertyChanged("category");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName){
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public void doCalculation(string calculationMode){
if(calculationMode == "Imperial"){
if (heightFt == null)
{
this.error = "You must provide a value for your height in feet!";
}
else if (heightIn == null)
{
this.error = "You must provide a value for your height in inches!";
}
else if (weightLbs == null)
{
this.error = "You must provide a value for your weight in pounds!";
}
else
{
heightFt = Convert.ToDouble(heightFt);
heightIn = Convert.ToDouble(heightIn);
weightLbs = Convert.ToDouble(weightLbs);
_weightKg = Convert.ToDouble(_weightLbs * (1 / 2.2));
_heightCm = Convert.ToDouble((_heightFt + (_heightIn / 12) / 0.032808));
}
} else if(calculationMode == "Metric"){
this.bmi = weightKg / Math.Pow((heightCm / 100), 2);
if (this.bmi < 18.5)
{
this.category = "underweight";
}
else if (this.bmi >= 18.5 && this.bmi < 24.9)
{
this.category = "normalweight";
}
else if (this.bmi >= 25 && this.bmi <= 29.9)
{
this.category = "overweight";
}
else if (this.bmi > 30)
{
this.category = "obese";
}
}
}
}
}
}
You can make you double properties to be nullable so you can compare to null (the default).
Example:
public double? heightIn
{
get { return _heightIn; }
set {
_heightIn = value;
OnPropertyChanged("heightIn");
}
}
In this case, make sure you change the type of the corresponding private variables to match.
You never set a default value for your properties. As double cannot be null you'll probably want to check against 0 instead. The properties you begin with underscores should just be private variables with default values. Also consider using metric only internally.
class BMICalc :INotifyPropertyChanged
{
private double _heightFt = 0;
private double _heightIn = 0;
private double _heightCm = 0;
private double _weightLbs = 0;
private double _weightKg = 0;
private double _bmi = 0;
private string _category = null;
private string _error = null;
public double heightFt
{
get { return _heightFt; }
set
{
_heightFt = value;
OnPropertyChanged("heightFt");
}
}
public double heightIn
{
get { return _heightIn; }
set
{
_heightIn = value;
OnPropertyChanged("heightIn");
}
}
public double heightCm
{
get { return _heightCm; }
set
{
_heightCm = value;
OnPropertyChanged("heightCm");
}
}
public double weightLbs
{
get { return _weightLbs; }
set
{
_weightLbs = value;
OnPropertyChanged("weightLbs");
}
}
public double weightKg
{
get { return _weightKg; }
set
{
_weightKg = value;
OnPropertyChanged("weightKg");
}
}
public double bmi
{
get { return _bmi; }
set
{
_bmi = value;
OnPropertyChanged("bmi");
}
}
public string error
{
get { return _error; }
set
{
_error = value;
OnPropertyChanged("error");
}
}
public string category
{
get { return _category; }
set
{
_category = value;
OnPropertyChanged("category");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName){
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public void doCalculation(string calculationMode){
if(calculationMode == "Imperial"){
if (heightFt == null)
{
this.error = "You must provide a value for your height in feet!";
}
else if (heightIn == null)
{
this.error = "You must provide a value for your height in inches!";
}
else if (weightLbs == null)
{
this.error = "You must provide a value for your weight in pounds!";
}
else
{
heightFt = Convert.ToDouble(heightFt);
heightIn = Convert.ToDouble(heightIn);
weightLbs = Convert.ToDouble(weightLbs);
_weightKg = Convert.ToDouble(_weightLbs * (1 / 2.2));
_heightCm = Convert.ToDouble((_heightFt + (_heightIn / 12) / 0.032808));
}
} else if(calculationMode == "Metric"){
this.bmi = weightKg / Math.Pow((heightCm / 100), 2);
if (this.bmi < 18.5)
{
this.category = "underweight";
}
else if (this.bmi >= 18.5 && this.bmi < 24.9)
{
this.category = "normalweight";
}
else if (this.bmi >= 25 && this.bmi <= 29.9)
{
this.category = "overweight";
}
else if (this.bmi > 30)
{
this.category = "obese";
}
}
}
}
}
I have a question. How can i validate my price in property to be positive number, else to throw a new exception.
I have already tried it that way, but still doesn't work:
public decimal Price
{
get
{
{ return this.price; }
}
set
{
if (this.price < 0)
{
throw new ArgumentException("The price should be positive!");
}
else
{
this.price = value;
}
}
}
Now i see, you are checking against the backing field in the setter of the property which has the last value or the default value 0 if it was not yet initialized. Use the value instead:
private decimal price;
public decimal Price
{
get
{
{ return this.price; }
}
set
{
if (value < 0)
{
throw new ArgumentException("The price should be positive!");
}
else
{
this.price = value;
}
}
}
The part this.price is the current value. You need to check the value that is passed in the setter using the value variable.
public decimal Price
{
get
{
{ return this.price; }
}
set
{
if (value < 0)
{
throw new ArgumentException("The price should be positive!");
}
else
{
this.price = value;
}
}
}