Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Assuming I have an enum category with some values:
enum Category {
ProgrammingBooks
CookingBooks
}
and I want each enum to have his own enum, for instance:
ProgrammingBooks will hold:
enum ProgrammingBooks {
CSharp,
Java,
Cpp
}
I saw a solution suggesting this:
enum Fauna {
enum Type { MAMMAL, BIRD }
TIGER(Type.MAMMAL),
LION(Type.MAMMAL),
PEACOCK(Type.BIRD),
OWL(Type.BIRD);
private final Type type;
Fauna(Type type) { this.type = type; }
}
with the usage:
Stream.of(Fauna.values()).filter(f -> f.type == BIRD).toList()
However, I'm just a beginner and I look for something that even if I do not know and should learn, wont go hardcore on me. I do not understand the example I mentioned (which I found on StackOverFlow).
Use classes or interfaces. For example:
public enum Category
{
ProgrammingBooks,
CookingBooks
}
public interface IBook
{
Category BookType { get; set; }
string Title { get; set; }
string Author { get; set; }
// ...
}
public class ProgrammingBook: IBook
{
public ProgrammingBook()
{
this.BookType = Category.ProgrammingBooks;
}
public string Author { get; set; }
public string Title { get; set; }
public Category BookType { get; set; }
// ...
}
public class CookBook : IBook
{
public CookBook()
{
this.BookType = Category.CookingBooks;
}
public string Author { get; set; }
public string Title { get; set; }
public Category BookType { get; set; }
// ...
}
If you want to support "sub-types" you could provide properties that only belong to a specific class and not into the interface because not every book is about programming. For example:
public enum ProgrammingLanguage
{
CSharp,
Java,
Cpp
}
public class ProgrammingBook: IBook
{
// a constructor that takes the ProgrammingLanguage as argument
public ProgrammingBook(ProgrammingLanguage language)
{
this.BookType = Category.ProgrammingBooks;
this.Language = language;
}
public ProgrammingLanguage Language { get; set; }
public string Author { get; set; }
public string Title { get; set; }
public Category BookType { get; set; }
// ...
}
Why i use interfaces at all? Because all books have something in common(f.e. they all have a title and an author). So you can benefit from Polymorphism:
var library = new List<IBook>();
var book1 = new ProgrammingBook(ProgrammingLanguage.CSharp) {Title = "C# in Depth", Author = "Jon Skeet"};
var book2 = new CookBook() { Title = "Everyday Superfood", Author= "Jamie Oliver" };
library.Add(book1);
library.Add(book2);
// now you can loop all and you know that all books have these properties
foreach (IBook book in library)
{
Console.WriteLine("Title: {0} Type: {1}", book.Title, book.BookType.ToString());
}
or if you only want to get programming-books:
foreach (IBook book in library.Where(b => b.BookType == Category.ProgrammingBooks))
{
// ...
}
the same with LINQ's Enumerable.OfType method which just checks the type:
foreach (IBook book in library.OfType<ProgrammingBook>())
{
// ....
}
Enum is just a representation of an integer with text. It cannot hold sub categories or anything but an integer.
You should create a class for the categories and hold an enum of the sub categories in each of them.
public class ProgrammingBook
{
public BookType Type{get;set;}
}
enum BookType {
CSharp,
Java,
Cpp
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 months ago.
Improve this question
I have an issue reading values (nationalId,surname,givenNames) from a nested json object below. Getting the error System.ArgumentNullException: Value cannot be null. (Parameter 'value')
Below is my Json string and Code respectively;
{
"return": {
"transactionStatus": {
"transactionStatus": "Ok",
"passwordDaysLeft": 35,
"executionCost": 0.0
},
"nationalId": "123456789",
"surname": "JOHN",
"givenNames": "DOE"}}
C# CODE, WHERE person_jObject Holds The JSON Above
JObject person_jObject = JObject.Parse(content5);
person.nationalId = person_jObject["nationalId"].Value<string>();
person.surname = person_jObject["surname"].Value<string>();
person.givenNames = person_jObject["givenNames"].Value<string>();
This should get you what you want:
// Usage:
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
//
public class Return
{
public TransactionStatus transactionStatus { get; set; }
public string nationalId { get; set; }
public string surname { get; set; }
public string givenNames { get; set; }
}
public class Root
{
public Return #return { get; set; }
}
public class TransactionStatus
{
public string transactionStatus { get; set; }
public int passwordDaysLeft { get; set; }
public double executionCost { get; set; }
}
From https://json2csharp.com/
Of course, this won't help you if your Person object is broken.
you have a bug in your code, you need to use root "return" property
person.nationalId = person_jObject["return"]["nationalId"].Value<string>();
but you don't need to assign each property, if you need just person, just parse your json and deserialize a person part only
Person person=JObject.Parse(content5)["return"].ToObject<Person>();
assuming that your class person is like this
public class Person
{
public string nationalId { get; set; }
public string surname { get; set; }
public string givenNames { get; set; }
... could be another properties
}
I reposted question on codereview but can not delete this question couse already answer here.
I have some classes:
public abstract class House
{
public string Name { set; get;}
public SomeClass Property1 { set; get;}
public OtherClass Property2 { set; get;}
}
public class WoodenHouse:House
{
public string WoodType { set; get;}
public int WoodAge { set; get;}
}
public class StoneHouse:House
{
public string StoneType { set; get;}
}
And trying to create Factory Method pattern for this:
abstract class Creator
{
public abstract HouseInfo Info { get; set; }
public Creator()
{
}
public abstract House FactoryMethod();
}
class WoodenHouseCreator : Creator
{
public override HouseInfo Info { get; set; }
public WoodenHouseCreator(WoodenHouseInfo info)
{
Info = info;
}
public override House FactoryMethod()
{
var info = Info as WoodenHouseInfo;
var woodenHouse = new WoodenHouse();
woodenHouse.Name = info.Name;
woodenHouse.Floors = info.Floors;
woodenHouse.RoofType = info.RoofType;
woodenHouse.WoodType = info.WoodType;
woodenHouse.WoodAge = info.WoodAge;
return woodenHouse;
}
}
class StoneHouseCreator : Creator
{
public override HouseInfo Info { get; set; }
public StoneHouseCreator(StoneHouseInfo info)
{
Info = info;
}
public override House FactoryMethod()
{
var info = Info as StoneHouseInfo;
var stoneHouse = new StoneHouse();
stoneHouse.Name = info.Name;
stoneHouse.Floors = info.Floors;
stoneHouse.RoofType = info.RoofType;
stoneHouse.StoneType = info.StoneType;
return stoneHouse;
}
}
Here are the classes what contain information to create ahouse:
class HouseInfo
{
public string Name { set; get; }
public int Floors { set; get; }
public string RoofType { set; get; }
}
class WoodenHouseInfo : HouseInfo
{
public string WoodType { set; get; }
public int WoodAge { set; get; }
}
class StoneHouseInfo : HouseInfo
{
public string StoneType { set; get; }
}
And Usage:
var houseInfo = new WoodenHouseInfo
{
Name = "HouseName",
Floors = 2,
RoofType = "Triangle",
WoodType = "Pine",
WoodAge = 100
};
House house;
if(houseInfo is WoodenHouseInfo)
{
var creator = new WoodenHouseCreator(houseInfo);
house = creator.FactoryMethod();
Console.Write((house as WoodenHouse).WoodAge);
}
Full code fiddle.
My problem is how to handle code duplication. I mean there is a lot of lines that fills base House object properties. How can I write that code only once?
Or I should not to use Factory Method?
Currently your factories instantiate the new objects and then fill in all of their properties with the right values. You could split instantiation from property value assignment. Your StoneHouseCreator could instantiate a StoneHouse, use a HousePopulator that populates the values that all objects of type House have in common, and then the StoneHouseCreator could populate the rest of the values that are exclusive to a StoneHouse. That same HousePopulator could also be used by your WoodenHouseCreator, which would then proceed to populate the WoodenHouse-specific properties.
If you want to philosophise about this at a higher level, these are the problems that we run into because of inheritance. Factories, that is the logical separation of object use from object creation, are more naturally suited to cases where you use composition over inheritance. If you are interested more in this, I would recommend reading this excellent article on the topic.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm starting my adventure with C# and don't know all the technics, but I already know what am I trying to achive:
public class Product
{
public string Name { get; set; }
public double Price { get; set; }
//public ??? Category { get; set; }
}
'Category' type should be a custom type (?) which has 8 possible string values for names (Food, clothes etc) and icons specifically for those names (Food - apple.jpg, Clothes - tshirt.jpg and so on)
How do I do that?
Often, when working with fixed size categories (8 in your case) we use enum type:
public enum ProductCategory {
Food,
Clothes,
//TODO: put all the other categories here
}
To add up icons, strings etc. we can implement extension methods:
public static class ProductCategoryExtensions {
// please, notice "this" for the extension method
public static string IconName(this ProductCategory value) {
switch (value) {
case ProductCategory.Food:
return "apple.jpg";
case ProductCategory.Clothes:
return "tshirt.jpg";
//TODO: add all the other categories here
default:
return "Unknown.jpg";
}
}
}
Finally
public class Product {
public string Name { get; set; }
public double Price { get; set; } // decimal is a better choice
public ProductCategory Category { get; set; }
}
Usage
Product test = new Product();
test.Category = ProductCategory.Clothes;
Console.Write(test.Category.IconName());
You can define the Category class like the following with predefined values:
public class Category
{
public static Category Food = new Category("Food", "apple.jpg");
// rest of the predefined values
private Category(string name, string imageName)
{
this.ImageName = imageName;
this.Name = name;
}
public string Name { get; private set; }
public string ImageName { get; private set; }
}
public class Product
{
public string Name { get; set; }
public double Price { get; set; }
public Category Category { get; set; }
}
Then, in your code you can set a product like this:
var product = new Product {Name= "product1", Price=1.2, Category = Category.Food};
So first of all you create a new Class, your custom type
public class Category {
// I recommend to use enums instead of strings to archive this
public string Name { get; set; }
// Path to the icon of the category
public string Icon { get; set; }
}
Now in your product, you can change the line commented out to:
// First Category is the type, the second one the Name
public Category Category { get; set; }
Now you can create a new Product with a category:
var category = new Product() {
Name = "ASP.NET Application",
Price = 500,
Category = new Category() {
Name = "Software",
Icon = "Software.jpg"
}
}
Now when you want to create another Product with another category, just repeat the proccess. You can also create an array of Categories and then use the array elements e.g. Category = Categories[3]. So you create one Category for food, one for Clothes etc, store them all in the array and use them for your products.
Starting off, I'm working with EF, since I'm building an MVC application on C#. I want different types of exams to have different types of questions. Here are my abstract classes:
public abstract class Exam
{
public int Id { get; set; }
public string Description { set; get; }
public abstract ICollection<Question> GetQuestions();
public abstract void SetQuestions(ICollection<Question> questions);
}
public abstract class Question
{
public int Id { get; set; }
public string Description { set; get; }
public abstract Exam getExam();
public abstract void setExam(Exam exam);
}
Notice that instead of the typical public virtual ICollection<Question> in the Exam class declaration, I created an abstract setter and getter. So is the case for the Exam property in the Question class.
Here are my concrete Exam classes:
[Table("SingleExam")]
public class SingleExam : Exam
{
public virtual ICollection<SingleQuestion> Questions { get; set; }
public override ICollection<Question> GetQuestions() { return Questions as ICollection<Question>; }
public override void SetQuestions(ICollection<Question> questions)
{
if (!(questions is ICollection<SingleQuestion>))
throw new ArgumentException("You must set single questions.");
Questions = questions as ICollection<SingleQuestion>;
}
}
[Table("MultipleExam")]
public class MultipleExam : Exam
{
public virtual ICollection<MultipleQuestion> Questions { get; set; }
public override ICollection<Question> GetQuestions() { return Questions as ICollection<Question>; }
public override void SetQuestions(ICollection<Question> questions)
{
if (!(questions is ICollection<MultipleQuestion>))
throw new ArgumentException("You must set multiple questions.");
Questions = questions as ICollection<MultipleQuestion>;
}
}
...And my concrete Question classes:
[Table("SingleQuestion")]
public class SingleQuestion : Question
{
public int ExamId { get; set; }
public virtual SingleExam Exam { get; set; }
public override Exam getExam() { return Exam; }
public override void setExam(Exam exam)
{
if (!(exam is SingleExam))
throw new ArgumentException("You must set a SingleExam");
Exam = exam as SingleExam;
}
}
[Table("MultipleQuestion")]
public class MultipleQuestion : Question
{
public int ExamId { get; set; }
public virtual MultipleExam Exam { get; set; }
public override Exam getExam() { return Exam; }
public override void setExam(Exam exam)
{
if (!(exam is MultipleExam))
throw new ArgumentException("You must set a MultipleExam");
Exam = exam as MultipleExam;
}
}
I did all this because a MultipleExam should only have MultipleQuestions, and a SingleExam should only have SingleQuestions, the same way that MultipleQuestion should have a MultipleExam and Single question should have a SingleExam.
Is there a better way to ensure that a subclass of a class 'A' contains or has a specific subclass of class 'B' (As is the case with my Exams and Questions), and having access to it through the abstract class without the abstract getters and setters?
As other have mentioned I think you are over complicating your problem.
However; your question is about type guarantees and I will try to answer that.
First the code:
public interface IExam<out T> where T:IQuestion {
int Id { get; set; }
string Description { set; get; }
IEnumerable<T> GetQuestions();
}
public interface IQuestion{
int Id { get; set; }
string Description { set; get; }
IExam<IQuestion> Exam { get; }
}
public class SingleQuestion:IQuestion {
public string Description { get; set; }
public int Id { get; set; }
IExam<IQuestion> IQuestion.Exam {
get { return Exam; }
}
public SingleExam Exam { get; set; }
}
public class SingleExam:IExam<SingleQuestion> {
public int Id { get; set; }
public string Description { get; set; }
private IEnumerable<SingleQuestion> _questions;
public IEnumerable<SingleQuestion> GetQuestions() {
return _questions;
}
public void SetQuestions(IEnumerable<SingleQuestion> questions) {
_questions = questions;
}
}
First of all we have replaced the abstract classes with interfaces.
This is required because we want to make IExam covariant on IQuestion and covariance can only be defined in an interface. This is also why we change to an IEnumerable for the collection.
Note we do not define the SetQuestions method in IExam in short this is because we can't. In long it is because that would make T contravarient as well as contravarient which would in turn lead to circumstances where type guarantees could not be made.
IQuestions is fairly straight forward no real changes here. You could, I suppose, leave it as an abstract type though.
Now the implementations:
In SingleQuestion we must explicitly implement Exam which expects an IExam then shadow it with a property that returns a SingleExam.
This allows us to return the most exact type of exam possible.
SingleQuestion sq = new SingleQuestion();
IQuestion q = sq; //Upcast
sq.Exam; //returns a SingleExam
q.Exam; //returns a IExam<IQuestion>
In SingleExam you can now set the questions and restrict it so that only SingleQuestions may be added.
As an aside it is now easier to see why SetQuestions cannot be defined in IExam. Consider the following:
SingleExam se = new SingleExam();
IExam<IQuestion> singleUpcast = se;
//What type of question can we set on singleUpcast?
All we know is that singleUpcast contains IQuestions but we can't just add IQuestions because singleUpcast is ultimately an instance of SingleExam which promised that only SingleQuestions could be set so it. In short it is not possible to know what types can be added to IExam without potentially breaking type guarantees
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have the following classes
class ClassA : SuperClass { }
class ClassB : SuperClass { }
class ClassC : SuperClass { }
class SuperClass
{
int Id { get; set; }
string Property1 { get; set; }
string Property2 { get; set; }
List<string> Property3 { get; set; }
}
When a condition is met, I have to override one, two or all of the properties in any of the classes (A, B, C) and I have to know that the properties were overridden and which ones where.
So I created this interface that should be implemented by SuperClass.
public interface IOverride
{
string OverrideProperty1 { get; set; }
string OverrideProperty2 { get; set; }
List<string> OrderedProperty3 { get; set; }
}
How can I know if a property was overridden without having to create a boolean for each property.
Or should I go for a different approach?
EDIT
ClassA, ClassB and ClassC data come from a specific source and for each of the objects I get information from another source. If the new source has values I need to stored them and override the original ones.
Something like
var dataList = GetClassesData() as List<SuperClass>;
var newData = GetNewData() as object[];
foreach (var data in dataList)
{
if (newData.Contains(o => o.Id == data.Id))
{
data.Property1 = newData[Id].Property1;
data.Property2 = newData[Id].Property2;
data.Property3 = newData[Id].Property3;
}
}
Overriding itself is not intent to be conditional, what can be conditional, is the value of the property you return from overridden class.
This should do it for you.
if(typeof(ClassA).GetMethod("Property1").DeclaringType == typeof(SuperClass)){
//This method was overridden
}
If I understand your edited question right, you could put it like that:
public interface IOverride
{
string StandardProperty1 { get; set; }
string StandardProperty2 { get; set; }
List<string> StandardProperty3 { get; set; }
string OverrideProperty1 { get; set; }
string OverrideProperty2 { get; set; }
List<string> OrderedProperty3 { get; set; }
}
class ClassA : SuperClass { }
class ClassB : SuperClass { }
class ClassC : SuperClass { }
class SuperClass : IOverrideProperty
{
string StandardProperty1 { get; set; }
string StandardProperty2 { get; set; }
List<string> StandardProperty3 { get; set; }
string OverrideProperty1 { get; set; }
string OverrideProperty2 { get; set; }
List<string> OrderedProperty3 { get; set; }
string Property1
{
get
{
if (condition)
return OverrideProperty1;
else
return StandardProperty1;
}
set
{
if (condition)
OverrideProperty1 = value;
else
StandardProperty1 = value;
}
//Same for Property2 and 3
}
You can now set both Properties and your condition will decide wich one is returned or set.