C# limit options of enum in a derived class - c#

So I'm trying to limit the options ,of an enum I declared in the base class, I can select in the derived class.
namespace FLYNET.Personeel
{
public enum Graad
{
Captain,
SeniorFlightOfficer,
SecondOfficer,
JuniorFlightOfficer,
Steward,
Purser
};
public abstract class VliegendPersoneelslid : Personeelslid
{
public VliegendPersoneelslid()
{
}
public override decimal BerekenTotaleKostprijsPerDag()
{
return BasisKostprijsPerDag;
}
public List<Certificaat> Certificaten { get; set; }
}
The above is the enum I'm trying to use from the base class Staff.
In the derived class Cabincrew I want to limit the options that can be selected in the constructor. If the wrong option is selected, it needs to throw a specified exception, so a bit like this :
namespace FLYNET.Personeel
{
public class CockpitPersoneel : VliegendPersoneelslid
{
public int VliegUren { get; set; }
public Graad Graad { get; set; }
public CockpitPersoneel()
{
if (Grade = Graad.Steward || Grade = Graad.Purser)
{
throw new Exception
}
}
public override decimal BerekenTotaleKostprijsPerDag()
{
decimal kostprijsPersoneel = 0m;
decimal percentage;
return kostprijsPersoneel;
}
}
}
I'm aware this is probably a beginners question (and it is :p) but please bear with me.

I suggest using extension methods in order to hide options
public enum Grade {
None, // <- zero option is often a good idea to include
Captain,
SeniorFlightOfficer,
SecondOfficer,
JuniorFlightOfficer,
Steward,
Purser };
public static class GradeExtensions {
public static bool IsCabinCrue(this Grade grade) {
return grade == Grade.Steward || grade == Grade.Purser;
}
public static bool IsCockpitPersonnel(this Grade grade) {
return grade == Grade.Captain ||
grade == Grade.SeniorFlightOfficer ||
grade == Grade.SecondOfficer ||
grade == Grade.JuniorFlightOfficer;
}
}
Then you can use extension methods as if their are methods of the enum when validating Grade values provided:
public class CabinCrue {
...
public CabinCrue(Grade grade) {
// Validation: Cabin Crue grade only
// not Exception but ArgumentException: it's argument grade that's wrong
if (!grade.IsCabinCrue())
throw new ArgumentException("Cabin crue only", "grade");
Grade = grade;
...
}
public Grade Grade {
get;
private set;
}
...
}

I think you have an error in logic. You are trying to verify the Grade or Graad in the constructor. The property Graad cannot be set before the constructor call. Your validation will check the default value of the variable Graad (which in your case will be Captain).
You would need to pass the Graad into the constructor to be able to make that validation:
public CockpitPersoneel(Graad g)
{
if (g = Graad.Steward || g = Graad.Purser)
{
throw new Exception("wrong choice");
}
else
{
this.Graad = g;
}
}
What you also could do is to put the Validation logic directly into the full property and throw there the exception:
Graad _myGrade;
public Graad GradeOfPerson
{
get { return _myGrade; }
set
{
if (value = Graad.Steward || value = Graad.Purser)
{
throw new Exception("Not Allowed");
}
_myGrade = value;
}
}
this way you can leave your constructor blank:
public CockpitPersoneel()
{
}

Related

Converting objects to Subclass

I want to make a class Vehicle and two classes (PassengerVehicle and FreightVehicle) that inherit it. The problem is that when the user enters the type of vehicle he wants and when I convert an object from Vehicle to the desired type, I can't use those class methods later. Here is my code, how can I fix this?
using System;
namespace Vehicle_Primer
{
enum FuelType
{
Gas,
Diesel
}
class Vehicle
{
private FuelType FuelType { get; set; }
}
class PassengerVehicle : Vehicle
{
private int SeatNumber { get; set; }
private int PassengerNumber { get; set; }
public void CheckSeats()
{
if (PassengerNumber > SeatNumber) Console.WriteLine("Not enough seats");
else Console.WriteLine("Enough seats");
}
}
class FreightVehicle : Vehicle
{
private int Capacity { get; set; }
private int Mass { get; set; }
public void CheckCapacity()
{
if (Mass > Capacity) Console.WriteLine("Load capacity exceeded");
else Console.WriteLine("Load capacity not exceeded");
}
}
internal class Program
{
static void Main()
{
Vehicle vehicle = null;
while (true)
{
Console.WriteLine("Enter vehicle type");
string input = Console.ReadLine();
if (input == "passenger")
{
vehicle = new PassengerVehicle();
break;
}
else if (input == "freight")
{
vehicle = new FreightVehicle();
break;
}
Console.WriteLine("Wrong input");
}
if (vehicle is FreightVehicle)
{
vehicle.CheckCapacity();
}
else
{
vehicle.CheckSeats();
}
}
}
}
I think the problem here is you are not using properly pattern matching. When using pattern matching you need to declare a variable to test against, like as follow:
if (vehicle is FreightVehicle freight)
{
freight.CheckCapacity();
}
else if (vehicle is PassengerVehicle passenger)
{
passenger.CheckSeats();
}
In other words, when using pattern matching, it implicitly forces you to declare the variable to test, and if the type is correct you can use that object and its methods and properties.
For a more detailed expalanation, you can see this link at Type Tests.
Another option is to restructure your program to use the concrete type directly, although this mixes IO and non-IO a bit:
static void Main()
{
Vehicle vehicle = null;
while (true)
{
Console.WriteLine("Enter vehicle type");
string input = Console.ReadLine();
if (input == "passenger")
{
PassengerVehicle vehicle = new PassengerVehicle();
vehicle.CheckSeats();
break;
}
else if (input == "freight")
{
FreightVehicle vehicle = new FreightVehicle();
vehicle.CheckCapacity();
break;
}
Console.WriteLine("Wrong input");
}
}

C# Accessing a property within a property?

I'm trying to pass some tests in the Exercism C# exercise 'weighing machine' which uses properties. I have these properties:
using System;
enum Units
{
Pounds,
Kilograms
}
class WeighingMachine
{
private decimal inputWeight;
public decimal InputWeight
{
get { return inputWeight; }
set { if (value >= 0)
inputWeight = value;
else throw new ArgumentOutOfRangeException();
}
}
private decimal displayWeight;
public decimal DisplayWeight
{
get
{ return displayWeight; }
set
{
displayWeight = InputWeight - TareAdjustment;
if (displayWeight <= 0)
throw new ArgumentOutOfRangeException();
}
}
private decimal _pounds;
public USWeight USDisplayWeight
{
get { return _pounds; }
set { _pounds = new USWeight(InputWeight).Pounds; }
}
public decimal TareAdjustment { private get; set; }
public int Units
{ get; set; }
}
struct USWeight
{
public USWeight(decimal weightInPounds)
{
Pounds = (int)weightInPounds;
Ounces = (weightInPounds - Pounds)*16;
}
public int Pounds { get; set; }
public decimal Ounces { get; set; }
}
My stumbling block is the tests:
[Fact]
public void Get_us_display_weight_pounds()
{
var wm = new WeighingMachine();
wm.InputWeight = 60m;
Assert.Equal(132, wm.USDisplayWeight.Pounds);
}
I can't get my head around how the test is asking for wm.USDisplayWeight.Pounds - how is the .Pounds accessed on the end? it's like there is a property set within the USDisplayWeight property, but that's not possible is it? I can't make the compiler stop complaining about the .Pounds - I get ''decimal' does not contain a definition for 'Pounds' and no accessible extension method 'Pounds' accepting a first argument of type 'decimal' could be found.
I'm sure it's a simple thing that I'm overlooking here, but I would appreciate any help at all.

Is there a way to access T.Method() in a new instance of T in a generic method?

I have a generic method
class Program {
Character CreateChar<T>() where T : new() {
T DChar = new T();
Character Char = new Character {
Name = DChar.Name,
Health = DChar.Health
};
return Char;
}
public static void Main() {
Character Char1 = CreateChar<Mage>();
}
}
Where I have a Character class, and that has the basic stuff like Name, Health, ect.
class Character {
public string Name { get; set; }
public int Health { get; set; }
}
But (this is like a game) I have some set types like "Mage".
class Mage {
public int Health {
get {
return 5;
}
}
}
So my idea was to make a generic method "CreateChar" so I can pass Mage to it like so in Main:
Character Char1 = CreateChar<Mage>();
However I can't seem to access DChar.Name or DChar.Health since "T does not contain a definition for 'Health'". So, is there a way to access the T method? Or is there just a better way of handling this?
In fact, now that I see it, "CreateChar();" is invalid as well because "an object reference is required for a nonstatic field". So I guess my question is, what is wrong, and how do I fix it?
In a generic method, you can only access the methods defined by the constraint on T (unless you use reflection or type checking/casting, both of which defeat the purpose of generics). If you constrain T to a Character (which I think you have to do to access Name and Health), then it should work (please post the Character class with relevant properties). But then in order to pass it a Mage, you'd have to have Mage inherit from Character.
Here's what I mean; first create an interface that defines properties that all characters will have (i.e. all public properties, methods, and events):
public interface ICharacter
{
string Name { get; set; }
string Description { get; }
int Health { get; set; }
}
Then we can create a base class called Character that implements the interface::
public class Character : ICharacter
{
public string Name { get; set; } = "Default Character";
public int Health { get; set; } = 5;
public string Description { get; protected set; } = "Default Description";
}
Next we create some character types that inherit the Character class:
public class Mage : Character
{
public Mage()
{
Name = "Default Mage";
Description = "Someone who uses or practices magic " +
"derived from supernatural or occult sources.";
}
}
public class Elf : Character
{
public Elf()
{
Name = "Default Elf";
Description = "A supernatural creature of folk tales, " +
"typically represented as a small, elusive figure " +
"in human form with pointed ears, magical powers, " +
"and a capricious nature.";
}
}
So now we can constrian our generic type T to the ICharacter interface, and we can access the Name and Health properties:
class Program
{
T CreateChar<T>() where T : ICharacter, new()
{
var result = new T();
result.Name += " (created in 'CreateChar' method)"; // Modify a property
return result;
}
// Rest of class omitted
}
You need to constrain T to an interface or a base class that contains the method you want to call.
I think you are looking at a factory pattern here. Does this help?
public class Character
{
protected Character(string name, int health)
{
Name=name;
Health=health;
}
public string Name { get; set; }
public int Health { get; set; }
}
public class Mage : Character
{
public Mage() : base("Evil Mage", 5)
{
this.Mana = 10;
}
public int Mana { get; set; }
}
public class Paladin : Character
{
public Paladin() : base("Holy Paladin", 8)
{
this.Shield = 2;
}
public int Shield { get; set; }
}
public static class ChatacterFactory
{
public static TChar Create<TChar>(string name) where TChar : Character, new()
{
var result = new TChar();
result.Name = name;
return result;
}
}
class Program
{
static void Main(string[] args)
{
Mage mage = ChatacterFactory.Create<Mage>("Boom Mage");
Paladin paladin = ChatacterFactory.Create<Paladin>("White Knight");
}
}
if I understood you right one of these should work for you:
//case 1
class Character1
{
static Character1 CreateChar<T>(T character) where T : CommonGameCharecterClassOrInterface, new()
{
Character1 achar = new Character1
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
class Character2
{
static Character2 CreateChar(dynamic character)
{
Character2 achar = new Character2
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
//case 2
class Character3
{
static Character3 CreateChar<T>() where T : CommonGameCharecterClassOrInterface, new()
{
T character = new T();
Character3 achar = new Character3
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}
class Character4
{
static Character4 CreateChar<T>() where T : new()
{
dynamic character = new T();
Character4 achar = new Character4
{
Name = character.Name,
Health = character.Health
};
return achar;
}
}

How to prevent property setter from modifying private property data

Let me explain my question by posing a hypothetical situation. Lets start with a class:
public class PaymentDetails
{
public int Id {get;set;}
public string Status {get;set;}
}
And then I have another class:
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public PaymentDetails MyPaymentDetails{ get { return _paymentDetails; } }
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
OK, so I have these two classes. PaymentHelper has made the property MyPaymentDetails read-only.
So I cannot instantiate PaymentHelper and modify MyPaymentDetails like this:
PaymentHelper ph = new PaymentHelper();
ph.MyPaymentDetails = new PaymentDetails(); // Not allowed!!!
But I can modify the public properties inside of ph.MyPaymentDetails like this:
ph.MyPaymentDetails.Status = "Some status"; // This is allowed
How do I prevent that from working? Or is there no good way of doing that?
A property may apply access modifiers to individual accessors, for instance:
public string Status { get; private set; }
The scope of access is left to your circumstance. Keeping it private, I'm sure you can tell, will mean only elements within the scope of the current class can use the setter, protected would allow inheritors to use it, etc.
Obviously your classes need to be engineered properly from the bottom up, so as to account for appropriate scoping and robust management when used further up the hierarchy.
The idea of protecting the properties of a complex type that is itself a property isn't available from a language construct at that level.
One option is to design the contained type in such a way as to make its properties read-only using the access modifiers (public set, protected set, private set, etc).
My preference is to expose it as an interface to public consumers:
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public IPaymentDetails MyPaymentDetails{ get { return _paymentDetails; } }
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
interface IPaymentDetails
{
int Status { get; }
}
Code inside the PaymentHelper class can then use the PaymentDetails class directly, and code outside the class won't be able to use PaymentDetails unless they cast directly to it, which you can stop if you don't release the PaymentDetails class and only provide the interface.
Of course, you can never really stop the determined person who may use reflection to set things. I tend to let these people break the code :-)
Another solution is not to expose the PaymentDetails object directly, but rather wrap the properties you wish to expose. For example:
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public string PaymentDetailsStatus { get { return _paymentDetails.Status; } }
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
Edit: You could always let the behavior of value types take care of this for you. Change PaymentDetails to a struct instead of a class:
public struct PaymentDetails
{
public int Id { get; set; }
public string Status { get; set; }
}
public class PaymentHelper
{
public PaymentDetails Details { get; set; }
}
If you then try to
ph.Details.Status = "Some status"; //
You'll get a compiler error telling you that you can't do this. Since value types are returned, well, by value, you can't modify the .Status property.
Or...
If PaymentDetails and PaymentHelper are declared in the same class library (separate from the code you want to prevent from writing to the .MyPaymentDetails property, you could use:
public class PaymentDetails
{
public int Id { get; internal set; }
public string Status { get; internal set; }
}
public class PaymentHelper
{
public PaymentDetails Details { get; private set; }
}
which will prevent anything declared outside of that class library from writing to .Id or .Status.
Or, force access to .Id and .Status to go through the helper class instead of allowing read access to a .Details property:
public class PaymentHelper
{
private PaymentDetails _details;
public string Id { get { return _details.Id; } private set { _details.Id=value; } }
public string Status { get { return _details.Status; } private set { _details.Status = value; } }
}
Of course, if you're going to do that, you could just
public calss PaymentDetails
{
public int Id { get; protected set; }
public string Status { get; protected set; }
}
public class PaymentHelper : PaymentDetails
{
}
... assuming that this sort of inheritance fits with the rest of your architecture.
Or, just to illustrate the interface suggestion proposed by #MrDisappointment
public interface IDetails
{
int Id { get; }
string Status { get; }
}
public class PaymentDetails : IDetails
{
public int Id { get; private set; }
public string Status { get; private set; }
}
public class PaymentHelper
{
private PaymentDetails _details;
public IDetails Details { get { return _details; } private set { _details = value; } }
}
So there are two ways that I can think of to deal with this. One is really simple:
public class PaymentDetails
{
private int _id;
private bool _idSet = false;
int Id
{
get
{
return _id;
}
set
{
if (_idSet == false)
{
_id = value;
_idSet == true;
}
else
{
throw new ArgumentException("Cannot change an already set value.");
}
}
}
private string _status;
private bool _statusSet = false;
string Status
{
get
{
return _status;
}
set
{
if (_statusSet == false)
{
_status = value;
_statusSet = true;
}
else
{
throw new ArgumentException("Cannot change an already set value.");
}
}
}
The simple solution only allows values to be set once. Changing anything requires creating a new instance of the class.
The other is rather complex but very versatile:
public interface IPaymentDetails : IEquatable<IPaymentDetails>
{
int Id { get; }
string Status { get; }
}
public class PaymentDetails : IPaymentDetails, IEquatable<IPaymentDetails>
{
public PaymentDetails()
{
}
public PaymentDetails(IPaymentDetails paymentDetails)
{
Id = paymentDetails.Id;
Status = paymentDetails.Status;
}
public static implicit operator PaymentDetails(PaymentDetailsRO paymentDetailsRO)
{
PaymentDetails paymentDetails = new PaymentDetails(paymentDetailsRO);
return paymentDetails;
}
public override int GetHashCode()
{
return Id.GetHashCode() ^ Status.GetHashCode();
}
public bool Equals(IPaymentDetails other)
{
if (other == null)
{
return false;
}
if (this.Id == other.Id && this.Status == other.Status)
{
return true;
}
else
{
return false;
}
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return base.Equals(obj);
}
IPaymentDetails iPaymentDetailsobj = obj as IPaymentDetails;
if (iPaymentDetailsobj == null)
{
return false;
}
else
{
return Equals(iPaymentDetailsobj);
}
}
public static bool operator == (PaymentDetails paymentDetails1, PaymentDetails paymentDetails2)
{
if ((object)paymentDetails1 == null || ((object)paymentDetails2) == null)
{
return Object.Equals(paymentDetails1, paymentDetails2);
}
return paymentDetails1.Equals(paymentDetails2);
}
public static bool operator != (PaymentDetails paymentDetails1, PaymentDetails paymentDetails2)
{
if (paymentDetails1 == null || paymentDetails2 == null)
{
return ! Object.Equals(paymentDetails1, paymentDetails2);
}
return ! (paymentDetails1.Equals(paymentDetails2));
}
public int Id { get; set; }
public string Status { get; set; }
}
public class PaymentDetailsRO : IPaymentDetails, IEquatable<IPaymentDetails>
{
public PaymentDetailsRO()
{
}
public PaymentDetailsRO(IPaymentDetails paymentDetails)
{
Id = paymentDetails.Id;
Status = paymentDetails.Status;
}
public static implicit operator PaymentDetailsRO(PaymentDetails paymentDetails)
{
PaymentDetailsRO paymentDetailsRO = new PaymentDetailsRO(paymentDetails);
return paymentDetailsRO;
}
public override int GetHashCode()
{
return Id.GetHashCode() ^ Status.GetHashCode();
}
public bool Equals(IPaymentDetails other)
{
if (other == null)
{
return false;
}
if (this.Id == other.Id && this.Status == other.Status)
{
return true;
}
else
{
return false;
}
}
public override bool Equals(Object obj)
{
if (obj == null)
{
return base.Equals(obj);
}
IPaymentDetails iPaymentDetailsobj = obj as IPaymentDetails;
if (iPaymentDetailsobj == null)
{
return false;
}
else
{
return Equals(iPaymentDetailsobj);
}
}
public static bool operator == (PaymentDetailsRO paymentDetailsRO1, PaymentDetailsRO paymentDetailsRO2)
{
if ((object)paymentDetailsRO1 == null || ((object)paymentDetailsRO2) == null)
{
return Object.Equals(paymentDetailsRO1, paymentDetailsRO2);
}
return paymentDetailsRO1.Equals(paymentDetailsRO2);
}
public static bool operator != (PaymentDetailsRO paymentDetailsRO1, PaymentDetailsRO paymentDetailsRO2)
{
if (paymentDetailsRO1 == null || paymentDetailsRO2 == null)
{
return ! Object.Equals(paymentDetailsRO1, paymentDetailsRO2);
}
return ! (paymentDetailsRO1.Equals(paymentDetailsRO2));
}
public int Id { get; private set; }
public string Status { get; private set;}
}
public class PaymentHelper
{
private PaymentDetails _paymentDetails;
public PaymentDetailsRO MyPaymentDetails
{
get
{
return _paymentDetails;
}
}
public PaymentHelper()
{
_paymentDetails = new PaymentDetails();
}
public void ModifyPaymentDetails(string someString)
{
// code to take the arguments and modify this._paymentDetails
}
}
The complex solution allows a changeable backing store, but presents a readonly version to the consumer that cannot be changed by outsiders to your helper class.
Note that both patterns only work if you implement them all the way down the object graph or stick to value types and strings.
You can't prevent that, the property returns a refrence to a PaymentDetails, and once somebody has that, it is out of your control.
However, you can just wrap the PaymentDetails. Instead of returning it verbatim, offer only getters for its public properties.
You can also assign access modifiers for the PaymentDetails class like so:
public string Status { get; private set; }
if you don't need the class elsewhere with a public setter.
Yet another solution: Make setters internal
This is the pragmatical way if the PaymentHelper is in the same assembly of PaymentDetails and the clients of PaymentHelper are in another assembly.
Yet another solution: Delegate from PaymentHelper to PaymentDetails.
This is to add the same properties to PaymentHelper as in PaymentDetails.
If you have many properties you can let generate the delegating properties into PaymentHelper by ReSharper. Place cursor on *_paymentDetails* of line
private PaymentDetails _paymentDetails;
Press Alt+Insert->Delegating Members. Then all PaymentHelper properties delegate to PaymentDetails properties.

Comparing 2 NHibernate loaded object problem

I have a class Client like that:
public class Client
{
public Person Pers { get; set; }
}
And I have 2 Person´s child class :
public class PersonType1 : Person {...}
public class PersonType2 : Person {...}
So, my Client could be PersonType1 or PersonType2...
I load 2 Client using NHibernate... And after that, I´m trying to compare than (the difference are on PersonType1 and PersonType2 attributes)...
I tried that:
public class ClientComparer : IComparer<Client>
{
public int Compare(Client __c1, Client __c2)
{
string _name1 = __c1.Person.GetType().Equals(typeof(PersonType2)) ? ((PersonType2)(__c1.Person)).Type2Att : ((PersonType1)(__c1.Person)).Type1Att ;
string _name2 = __c2.Person.GetType().Equals(typeof(PersonType2)) ? ((PersonType2)(__c2.Person)).Type2Att : ((PersonType1)(__c2.Person)).Type1Att;
if (_name1 == null)
{
if (_name2 == null)
{
return 0;
}
return -1;
}
if (_name2 == null)
{
return 1;
}
return _name1.CompareTo(_name2);
}
}
The problem is that __c1.Person.GetType() returs PersonProxy127b2a2f44f446089b336892a673643b instead of the correct type... It´s because of NHibernate...
How can I do that ? Ideas?
Thanks
Rather than having two different attributes on PersonType1 and PersonType2, define a single property in the base class Person and override it in each of the child classes. Using polymorphic behavior rather than explicit type-checking is better in any case, and essential when you're using NHibernate's proxied classes. Something like this might accomplish what you want:
public class Person
{
public string Name {get;}
}
public class PersonType2 : Person
{
private string something;
public override string Name
{
get
{
return something;
}
set
{
something = value;
}
}
}
public class PersonType2 : Person
{
private string somethingElse;
public override string Name
{
get
{
return somethingElse;
}
set
{
somethingElse = value;
}
}
}
public class Client
{
public int Compare(Client __c1, Client __c2)
{
return __c1.Pers.Name.CompareTo(__c2.Pers.Name);
}
}
Use the is operator instead of GetType():
public class ClientComparer : IComparer<Client>
{
public int Compare(Client __c1, Client __c2)
{
string _name1 = GetName(__c1.Person);
string _name2 = GetName(__c2.Person);
if (_name1 == null)
{
if (_name2 == null)
{
return 0;
}
return -1;
}
if (_name2 == null)
{
return 1;
}
return _name1.CompareTo(_name2);
}
private string GetName(Person person)
{
if (person is Person1)
{
return ((Person1)person).Type1Att;
}
else if (person is Person2)
{
return ((Person2)person).Type2Att;
}
else
{
throw new ArgumentException("Unhandled Person type.");
}
}
}

Categories

Resources