I have two interfaces. I want to use them for list and for array.
public interface IBook<T>
{
string Name { get; set; }
T Authors { get; set; }
int PagesCount { get; set; }
}
public interface IAuthor<T>
{
string Name { get; set; }
T Books { get; set; }
}
class Author<T> : IAuthor<IBook<T>[]>
where T : IAuthor<IBook<T>[]>
{
public string Name { get; set; }
public IBook<T>[] Books { get; set; }
}
class Book<T> : IBook<IAuthor<T>[]>
where T : IBook<IAuthor<T>[]>
{
public string Name { get; set; }
public IAuthor<T>[] Authors { get; set; }
public int PagesCount { get; set; }
public static void Main(string[] args)
{
Author<IBook<IAuthor<...>[]>[]> a = new Author<>();
}
}
Is there any way to create object like this in main. The compiler says there are no errors in description of interfaces and classes. Please help me.
Personally, I think that you may be over-using generics here and making this a little bit more complex than it is.Evaluate your criteria:
Author (one -> many) Book
Book (one -> many) Author
You can do this by having the following classes:
public class Book
{
public string Name { get; set; }
public Author[] Authors { get; set; }
public int PageCount { get; set; }
}
public class Author
{
public string Name { get; set; }
public Book[] Books { get; set; }
}
If you make it like this, you can make your life somewhat easier by containing all books and authors within a parent class and using linq queries to identify which object a book / author is related to:
public class BookStore
{
public List<Book> Books { get; set; }
public List<Author> Authors { get; set; }
public Book GetBook(string name)
{
var query = Books.Where(b => b.Name.Equals(name));
if (query.Count() == 1)
return query.ElementAt(0);
else return null;
}
public Author GetAuthor(string name)
{
var query = Authors.Where(a => a.Name.Equals(name));
if (query.Count() == 1)
return query.ElementAt(0);
else return null;
}
}
It would definitely be better for you if you don't use generic classes like this, cause this will be a pain in the neck every time you try to initialise an object. At least you make a default implementation for the generic class where it doesn't need to be given a type of author. You should definitely implement some kind of strategy for your application which will depend on how scalable it should be and easy to maintain and #Nathangrad has given you a great example.
I think your objects should look something like this where your Book's authors are not open to be changed directly and Author's books as well:
public interface IBook
{
string Name { get; set; }
ICollection<IAuthor> GetAuthors();
void AddAuthor(IAuthor book);
int PagesCount { get; set; }
}
public interface IAuthor
{
string Name { get; set; }
ICollection<IBook> GetBooks();
void AddBook(IBook book);
}
public class Author : IAuthor
{
private ICollection<IBook> books;
public Author()
{
this.books = new HashSet<IBook>();
}
public Author(ICollection<IBook> books)
{
this.books = books;
}
public string Name { get; set; }
public void AddBook(IBook book)
{
this.books.Add(book);
}
public ICollection<IBook> GetBooks()
{
return this.books;
}
}
public class Book : IBook
{
private ICollection<IAuthor> authors;
public Book()
{
this.authors = new HashSet<IAuthor>();
}
public Book(ICollection<IAuthor> Authors)
{
this.authors = Authors;
}
public void AddAuthor(IAuthor author)
{
this.authors.Add(author);
}
public ICollection<IAuthor> GetAuthors()
{
return this.authors;
}
public string Name { get; set; }
public int PagesCount { get; set; }
}
Related
After using http://json2csharp.com/ I got this stucture and I am trying to loop through all Books, however I don't know how and I guess there is a better way then to getting every Book list by hand like this BookStores[0].Prism.Books
In short I want to loop through every List<Book>
public class Book
{
public string name { get; set; }
public int pages { get; set; }
public double rating { get; set; }
public bool available { get; set; }
}
public class Prism
{
public List<Book> Books { get; set; }
}
public class Paragraphia
{
public List<Book> Books { get; set; }
}
public class BookStore
{
public Prism Prism { get; set; }
public Paragraphia Paragraphia { get; set; }
}
public class RootObject
{
public List<BookStore> BookStores { get; set; }
}
What about the following implementation.
public class Book
{
public string name { get; set; }
public int pages { get; set; }
public double rating { get; set; }
public bool available { get; set; }
}
public enum BookCategory
{
Prism,
Paragraphia
}
public class BookStore
{
public Dictionary<BookCategory, List<Book>> Books { get; set; }
}
And then use it as follows:
var bookStore = new BookStore();
bookStore.Books = new Dictionary<BookCategory, List<Book>>();
var paragrapiaBooks = new List<Book>();
paragrapiaBooks.Add(new Book{name = "Paragrapia book 1"});
paragrapiaBooks.Add(new Book{name = "Paragrapia book 2"});
bookStore.Books[BookCategory.Paragraphia] = paragrapiaBooks;
var prismBooks = new List<Book>();
prismBooks.Add(new Book{name = "Prism book 1"});
prismBooks.Add(new Book{name = "Prism book 2"});
bookStore.Books[BookCategory.Prism] = prismBooks;
foreach (var bookCategory in bookStore.Books)
{
foreach (var book in bookCategory.Value)
{
Console.WriteLine(book.name);
}
}
Console.ReadLine();
This way your implementation is also more flexible, you don't have to add a new property when you need a new book category, you just have to add a new Enum value. Instead of an Enum you can also use a String for example.
======================================================================
But I think the following solution is better, by adding property category to the Book class, because it is in fact a property of the book and not of the collection of books. A science fiction novel will still be science fiction even when it is placed on a bookshelf full of cookbooks.
public class Book
{
public string name { get; set; }
public int pages { get; set; }
public string category { get; set; }
public double rating { get; set; }
public bool available { get; set; }
}
public class BookStore
{
public List<Book> Books { get; set; }
}
And then use it as follows:
var bookStore = new BookStore();
bookStore.Books = new List<Book>();
bookStore.Books.Add(new Book { name = "Paragrapia book 1", category = "Paragrapia" });
bookStore.Books.Add(new Book { name = "Paragrapia book 2", category = "Paragrapia" });
bookStore.Books.Add(new Book { name = "Prism book 1", category = "Prism" });
bookStore.Books.Add(new Book { name = "Prism book 2", category = "Prism" });
Console.WriteLine("ONLY PRISM BOOKS:");
foreach (var book in bookStore.Books.Where(b => b.category == "Prism"))
{
Console.WriteLine(book.name);
}
Console.WriteLine("\r\nALL BOOKS:");
foreach (var book in bookStore.Books)
{
Console.WriteLine(book.name);
}
Console.ReadLine();
I have created classes using EF Code First that have collections of each other.
Entities:
public class Field
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<AppUser> Teachers { get; set; }
public Field()
{
Teachers = new List<AppUser>();
}
}
public class AppUser
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
public virtual List<Field> Fields { get; set; }
public AppUser()
{
Fields = new List<FieldDTO>();
}
}
DTOs:
public class FieldDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<AppUserDTO> Teachers { get; set; }
public FieldDTO()
{
Teachers = new List<AppUserDTO>();
}
}
public class AppUserDTO
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
public List<FieldDTO> Fields { get; set; }
public AppUserDTO()
{
Fields = new List<FieldDTO>();
}
}
Mappings:
Mapper.CreateMap<Field, FieldDTO>();
Mapper.CreateMap<FieldDTO, Field>();
Mapper.CreateMap<AppUserDTO, AppUser>();
Mapper.CreateMap<AppUser, AppUserDTO>();
And I am getting StackOverflowException when calling this code (Context is my dbContext):
protected override IQueryable<FieldDTO> GetQueryable()
{
IQueryable<Field> query = Context.Fields;
return query.ProjectTo<FieldDTO>();//exception thrown here
}
I guess this happens because it loops in Lists calling each other endlessly. But I do not understand why this happens. Are my mappings wrong?
You have self-referencing entities AND self-referencing DTOs. Generally speaking self-referencing DTOs are a bad idea. Especially when doing a projection - EF does not know how to join together and join together and join together a hierarchy of items.
You have two choices.
First, you can force a specific depth of hierarchy by explicitly modeling your DTOs with a hierarchy in mind:
public class FieldDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<TeacherDTO> Teachers { get; set; }
public FieldDTO()
{
Teachers = new List<TeacherDTO>();
}
}
public class TeacherDTO
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
}
public class AppUserDTO : TeacherDTO
{
public List<FieldDTO> Fields { get; set; }
public AppUserDTO()
{
Fields = new List<FieldDTO>();
}
}
This is the preferred way, as it's the most obvious and explicit.
The less obvious, less explicit way is to configure AutoMapper to have a maximum depth it will go to traverse hierarchical relationships:
CreateMap<AppUser, AppUserDTO>().MaxDepth(3);
I prefer to go #1 because it's the most easily understood, but #2 works as well.
Other option is using PreserveReferences() method.
CreateMap<AppUser, AppUserDTO>().PreserveReferences();
I use this generic method:
public static TTarget Convert<TSource, TTarget>(TSource sourceItem)
{
if (null == sourceItem)
{
return default(TTarget);
}
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var serializedObject = JsonConvert.SerializeObject(sourceItem, deserializeSettings);
return JsonConvert.DeserializeObject<TTarget>(serializedObject);
}
...
MapperConfiguration(cfg =>
{
cfg.ForAllMaps((map, exp) => exp.MaxDepth(1));
...
When you giving 1 navigation_property to 2nd entity and visa-versa it go in an infinite loop state. So, the compiler automatically throws a Stackoverflow exception.
So, to avoid that, you just need to remove one navigation_property from any of the entities.
I'm trying to create some interfaces. The IReportSection object will have one string and a collection of items, which could be different depending on what we're working with. Do I need to make it generic?
The IReport will have one string and a collection of IReportSection.
Here's how I'm trying to define it now.
public interface IReport
{
string ReportName { get; set; }
ICollection<IReportSection> ReportSections { get; }
}
public interface IReportSection
{
string ReportSectionName { get; set; }
ICollection ReportItems { get; }
}
public abstract class ReportSectionBase : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection ReportItems { get; set; }
}
And my models:
pulic class ProjectSubmissionViewModel
{
public int ProjectSubmissionId { get; set; }
public string SubmissionTitle { get; set; }
}
pulic class AffiliateViewModel
{
public int AffiliateId { get; set; }
public string AffiliateName { get; set; }
}
This is how I'm trying to use it in code:
public class ChapterAffiliates : ReportSectionBase
{
public string ReportSectionName { get { return "Chapter Affiliates"; } }
public ICollection<AffiliateViewModel> ReportItems { get; set; }
}
public class ChapterTitles : ReportSectionBase
{
public string ReportSectionName { get { return "Chapter Titles"; } }
public ICollection<ProjectSubmissionViewModel> ReportItems { get; set; }
}
public class SubmissionListViewModel : IReport
{
public ICollection<ProjectSubmissionViewModel> Submissions { get; set; }
public ICollection<AffiliateViewModel> Affiliates{ get; set; }
public string ReportName { get; set; }
public ICollection<IReportSection> ReportSections
{
get
{
var affiliateSection = new ChapterAffiliates
{
ReportItems = Affiliates
};
var titleSection = new ChapterTitles
{
ReportItems = Submissions.Where(s => s.SubmissionTitle.Contains("SomePhrase")).ToList()
};
var sections = new List<IReportSection> { {subSection}, {titleSection} };
return sections;
}
}
}
I'm not sure how to best define this. I'm pretty sure I've done it before, but it's not coming to me.
Are the type parameters for TRType all the same within a certain report? E.g. will you have report sections with different report types in them?
If all types within a report are the same, the solution is relatively simple:
public interface IReport<T> { ... }
If this is not the case - you'll have to do something different, e.g:
public interface IReportSection
{
string ReportSectionName { get; }
ICollection ReportItems { get; }
}
public abstract class ReportSectionBase<TRType> : IReportSection {
...
}
This allows you to put different underlying types in the ReportSections collection related to the report. You'll have to do some more work to get the exact information that you need out of each report section.
I'm having a problem defining these 2 classes:
public class Article
{
public Article(long ID, string Name, ArticleFamily Family)
{
//...Initializer...
}
public ArticleFamily Family { get; set; }
//Other props...
}
public class ArticleFamily
{
public ArticleFamily(int ID, string Description)
{
//...Initializer...
}
public int ID { get; private set; }
public string Description { get; set; }
}
I have a collection of Article and each one belongs to a family.
Now, given that I have a certain ArticleFamily object I should be able to change its Description and it gets eventually persisted to a DataBase. (I left out that part for simplicity)
But I should not be able to do this:
Article art = SomeMethodReturningArticle();
art.Family.Description = "SomeOtherValue";
I should be able to change the Family of an Article entirely, replacing it with a new ArticleFamily object, but I shouldn't be able to change just the description.
Should I create a copy of the ArticleFamily class with readonly properties like this:
public class ArticleFamilyReadonly
{
ArticleFamily _family;
public ArticleFamilyReadonly(ArticleFamily Family)
{
_family = Family;
}
public int ID { get { return _family.ID; } }
//etc...
}
How can I do this in a clean way?
Here's what I threw together in LinqPad:
void Main()
{
var art = new Article(1,"2", new ArticleFamily(1, "Test"));
art.Family.Description = "What?"; // Won't work
var fam = art.Family as ArticleFamily;
fam.Description = "This works"; // This works...
}
public class Article
{
public Article(long ID, string Name, IArticleFamily Family)
{
//...Initializer...
}
public IArticleFamily Family { get; set; }
//Other props...
}
public class ArticleFamily : IArticleFamily
{
public ArticleFamily(int ID, string Description)
{
//...Initializer...
}
public int ID { get; private set; }
public string Description { get; set; }
}
public interface IArticleFamily
{
int ID { get; }
string Description { get;}
}
Cannot edit directly from the Article object unless cast to ArticleFamily object.
I have 3 classes called Student,Worker,People which may come from different project.All of them have the two same property: name,age.Now when I want to change People to Student,I have to write a method called ChangePeopleToStudent, when I want to change People to Worker,I have to write a method called ChangePeopleToWorker.I try to use generic methods to write only one method,but it seems wrong.How to fix it?
Three classed
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public int MathPoint { get; set; }
}
public class Worker
{
public string Name { get; set; }
public int Age { get; set; }
public string WorkPlace { get; set; }
}
public class People
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
}
My two change method
public static Student ChangePeopleToStudent(People people)
{
return new Student
{
Name = people.Name,
Age = people.Age
};
}
public static Worker ChangePeopleToWorker(People people)
{
return new Worker
{
Name = people.Name,
Age = people.Age
};
}
Generic methods:How to fix it?
public static T ChangePeopleToWorker<T>(People people)
where T : Student, Worker,new T()
{
return new T
{
Name = people.Name,
Age = people.Age
};
}
Create an interface (or a base class - I'm assuming an interface in my example) e.g.:
public interface IPerson
{
string Name { get; set; }
int Age { get; set; }
}
It should be implemented by all your classes. Then you'll be able to write:
public static T ChangePersonTo<T>(IPerson person)
where T : IPerson, new T()
{
return new T
{
Name = person.Name,
Age = person.Age
};
}
.NET does not support multiple inheritance, so where T : Student, Worker is not a plausible condition. If you want T to be either Student or Worker you'll need to define a common base class (or interface), or define two different methods.
If People should be the common class between the two you can simplify your classes:
public class Student : People
{
public int MathPoint { get; set; }
}
public class Worker : People
{
public string WorkPlace { get; set; }
}
public class People
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
}