Readonly nested object properties - c#

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.

Related

Nested Object Acess to properties from Origin Object

Considering the following scheme.
A class that contains an object, in this case I'm using OriginObject.
The main problem is that the property NestedName has to access instructions about its behavior from another property within the OriginObject, in that case I thought about using reflection but, it's getting really confused.
The problem:
public class OriginObject
{
public NestedObject nestedObject { get; set; }
public Instructions Instruct { get; set; }
public class NestedObject
{
public string NestedName { get; set; }
public void GetName()
{
NestedName = //this.instruct.Name? being "this" the OriginObject;
}
}
public struct Instructions
{
public string Name { get; set; }
}
}
public void GetName()
{
NestedName = GetType().DeclaringType
.GetProperty("instruct")
.GetValue(GetType().DeclaringType)
.GetType()
.GetProperty("Name")
.GetValue(wtf im doing);
}
I know I can simply add a parameter that provides me the Origin Object but, in my logical base knowledge this means Clean and beautiful code:
/Target.DoSomething( );/
or in production terms speaking it will be something like
Body.Parse( );
Does somebody know any other way to do this? Without creating an ilegal crime of sequential methods?
If it's just a bad idea I can change it.
I understand that this is some code that you're just playing around with and that you're not really looking at having three classes to encapsulate one string...
With your code as it is, an instance of OriginObject.NestedObject does not hold onto a reference to an instance of OriginObject.
Having your classes nested is nice if you want to be able to access nonpublic members (methods, etc.) but everything in your code is public so there's no benefit there.
As there's no coupling (OriginObject.NestedObject and OriginObject.Instructions don't access any methods or static members on OriginObject) your code is equivalent to how they would be if there was no nesting.
You can probably see why your code won't work if you rewrite NestedObject and Instructions to not nested - you'd have this equivalent code:
public class OriginObject
{
public NestedObject nestedObject { get; set; }
public Instructions Instruct { get; set; }
}
public class NestedObject
{
public string NestedName { get; set; }
public void GetName()
{
NestedName = // How is NestedObject supposed to get anything from OriginObject?
}
}
public struct Instructions
{
public string Name { get; set; }
}
One fix would be to pass in an instance of OriginObject to a constructor of NestedObject, e.g.
public class OriginObject
{
public NestedObject Nested { get; set; }
public Instructions Instruct { get; set; }
public class NestedObject
{
private OriginObject _origin;
public NestedObject(OriginObject origin)
{
_origin = origin;
}
public string NestedName
{
get; set;
}
public void GetName()
{
NestedName = _origin.Instruct.Name;
}
}
public struct Instructions
{
public string Name { get; set; }
}
}
You'd then do something like this:
var instructions = new OriginObject.Instructions() { Name = "Test" };
var origin = new OriginObject() { Instruct = instructions };
var nested = new OriginObject.NestedObject(origin);
nested.GetName();
That was a bit clunky though - you have to pass in the OriginObject to the OriginObject.NestedObject, but you only ever use it to access the Instructions property. It'd be better if you just passed the Instructions object directly into the constructor, e.g.:
public class OriginObject
{
public NestedObject Nested { get; set; }
public Instructions Instruct { get; set; }
public class NestedObject
{
private Instructions _instructions;
public NestedObject(Instructions instructions)
{
_instructions = instructions;
}
public string NestedName
{
get; set;
}
public void GetName()
{
NestedName = _instructions.Name;
}
}
public struct Instructions
{
public string Name { get; set; }
}
}
which you'd use with something like this:
var instructions = new OriginObject.Instructions() { Name = "Test" };
var origin = new OriginObject() { Instruct = instructions };
var nested = new OriginObject.NestedObject(instructions);
nested.GetName();
Now, it's a bit weird to have a GetName() method that you have to call each time and doesn't return anything. Better still might be to get rid of the GetName() method and have the NestedName property a computed property instead:
public class OriginObject
{
public NestedObject Nested { get; set; }
public Instructions Instruct { get; set; }
public class NestedObject
{
private Instructions _instructions;
public NestedObject(Instructions instructions)
{
_instructions = instructions;
}
public string NestedName
{
get
{
return _instructions.Name;
}
}
}
public struct Instructions
{
public string Name { get; set; }
}
}
You'd then call that with an arguably simpler bit of code:
var instructions = new OriginObject.Instructions() { Name = "Test" };
var origin = new OriginObject() { Instruct = instructions };
var nested = new OriginObject.NestedObject(instructions);
At this point you might as well have a constructor for OriginObject too, so you know that the Instructions and the NestedObject instances are set - you could have something like this:
public class OriginObject
{
public NestedObject Nested { get; set; }
public Instructions Instruct { get; set; }
public OriginObject(NestedObject nested, Instructions instruct)
{
Nested = nested;
Instruct = instruct;
}
public class NestedObject
{
private Instructions _instructions;
public NestedObject(Instructions instructions)
{
_instructions = instructions;
}
public string NestedName
{
get
{
return _instructions.Name;
}
}
}
public struct Instructions
{
public string Name { get; set; }
}
}
which you'd use with some code like this:
var instructions = new OriginObject.Instructions() { Name = "Test" };
var nested = new OriginObject.NestedObject(instructions);
var origin = new OriginObject(nested, instructions);
Note that there's still no need for any nested types: you could have this equivalent code without nesting:
public class OriginObject
{
public NestedObject Nested { get; set; }
public Instructions Instruct { get; set; }
public OriginObject(NestedObject nested, Instructions instruct)
{
Nested = nested;
Instruct = instruct;
}
}
public class NestedObject
{
private Instructions _instructions;
public NestedObject(Instructions instructions)
{
_instructions = instructions;
}
public string NestedName
{
get
{
return _instructions.Name;
}
}
}
public struct Instructions
{
public string Name { get; set; }
}
which would be called with code like the following:
var instructions = new Instructions() { Name = "Test" };
var nested = new NestedObject(instructions);
var origin = new OriginObject(nested, instructions);

How to access a property in another class?

I am working with a WPF .Net Core 3 project.
In my UnbalancedViewModel I need to access an ID from another class (TestRunDto.cs).
UnbalancedViewModel
public class UnbalancedViewModel : ViewModelBase, IUnbalancedViewModel
{
private TestRunApi _testRunApi;
public UnbalancedViewModel(TestRunApi testRunApi, INotificationManager notifications)
{
_testRunApi = testRunApi;
}
private void StartTestRunJobExecuted(object obj)
{
_testRunApi.StartTestRun(1); ////I need the Id from TestRunDto (TestRunDto.Id)
}
}
TestRunApi
public async Task<TestRunLiveValueDto> GetTestRunLiveValue(int jobRunId)
{
await using var dbContext = new AldebaDbContext(_connectionString);
return await TestRunInteractor.GetTestRunLiveValue(jobRunId, dbContext);
}
public async Task StartTestRun(int testRunId)
{
await using var dbContext = new AldebaDbContext(_connectionString);
await TestRunInteractor.StartTestRun(dbContext, testRunId);
}
TestRunLiveValueDto
public class TestRunLiveValueDto
{
public TestRunDto TestRun { get; }
public bool ShowInstantaneousValue { get; set; }
public bool EnableStart { get; set; }
public bool EnableStop { get; set; }
public bool EnableMeasure { get; set; }
public int RecipeRpm { get; }
public string ActualRecipeName { get; }
public int DefaultSetOfPlaneId { get; }
public ICollection<BalancePlaneDto> ListBalancePlane { get; }
public ICollection<SetOfPlaneDto> ListSetOfPlane { get; }
public ICollection<SensorVibrationDto> SensorVibrations { get; set; }
public ICollection<EstimationDto> InstantaneousValues { get; set; }
public ICollection<EstimationDto> EstimationsValues { get; set; }
private TestRunLiveValueDto(TestRunDto testRun, bool enableStart, bool enableStop, int recipeRpm, ICollection<SensorVibrationDto> sensorVibrations)
{
EnableStart = enableStart;
EnableStop = enableStop;
TestRun = testRun;
RecipeRpm = recipeRpm;
SensorVibrations = sensorVibrations;
}
public static TestRunLiveValueDto Create(TestRunDto testRun, bool enableStart, bool enableStop, int recipeRpm, ICollection<SensorVibrationDto> sensorVibrations)
=> new TestRunLiveValueDto(testRun, enableStart, enableStop, recipeRpm, sensorVibrations);
}
TestRunDto
public class TestRunDto
{
public int Id { get; set; }
public int JobRunId { get; set; }
public string Name { get; set; }
public int TestRunNumber { get; set; }
public RunState State { get; set; }
public ICollection<BalancePlaneDto> BalancePlanes { get; set; } // Todo remove
private TestRunDto(int id, int jobRunId, RunState state, string name, int testRunNumber)
{
Id = id;
JobRunId = jobRunId;
Name = name;
TestRunNumber = testRunNumber;
State = state;
}
public static TestRunDto Create(int id, int jobRunId, RunState state, string name, int testRunNumber)
=> new TestRunDto(id, jobRunId, state, name, testRunNumber);
}
I have been trying to understand this, but I can not get a hold of the proper method to do this. Do I first declare a new TestRunDto class in my viewmodel or am I supposed to access it some other way?
You need to ensure class A has a reference to an instance of class B to access the properties, for example one way of doing this is to pass class A to B in a method where you can manipulate or access properties.
public class FooA
{
public string PropertyA { get; set; }
}
public class FooB
{
public string PropertyB { get; set; }
public void CanAccessFooA(FooA a)
{
a.PropertyA = "See, I can access this here";
}
}
Another is to pass class A to B in the constructor (known as dependency-injection)
public class FooB
{
FooA _a;
public FooB(FooA a)
{
// Pass instance of FooA to constructor
// (inject dependency) and store as a member variable
this._a = a;
}
public string PropertB { get; set; }
public void CanAccessFooA()
{
if (this._a != null)
this._a.PropertyA = "See, I can access this here";
}
}
Exactly how to structure your code is up to you, but the principle remains the same: Class B can only access Class A if it has a reference to an instance of it.
Look into 'Dependency Injection' as there are many techniques to achieve this.
Edit
One such technique might be abstracting the code to provide the ID to both, like so
public class IdProvider
{
public int Id { get; set; }
}
public class FooA
{
private int _id;
public FooA(IdProvider idProvider)
{
_id = idProvider.Id;
}
}
public class FooB
{
private int _id;
public FooB(IdProvider idProvider)
{
_id = idProvider.Id;
}
}
Now both classes have the same ID;
StartTestRun takes the tesRunId as it's parameter.
public async Task StartTestRun(int testRunId)
{
I think you need to call StartTestRunJobExecuted with this testRunId.
You will to change
private void StartTestRunJobExecuted(object obj)
to
private void StartTestRunJobExecuted(int testRunIdn)
{
_testRunApi.StartTestRun(testRunId); ////I need the Id from TestRunDto (TestRunDto.Id)
}
(This based on me guessing).

Two generics and infinity

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; }
}

Trying to work out these interfaces

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.

How to associate class property with instance property

I have some models for Person, TaskListitem and Task as shown below.
I am currently using BindingList to bind to datagrid to show task in datagrid. I am using it because I have to show DeveloperName and ReviewerName in the grid.
Background: this is a code from Task Tracking Program (learning project). Client is written in C#.
Server is written in Ruby. Server stores data in activerecord tables for People, Tasks.
Client also locally caches the same in sqlite DB.
Currently Globals.People is defined as
public static class Globals
{
...
public static List<Person> People = new List<Person>();
...
}
and the classes Person, TaskListitem and Task as shown below:
public class Person : TimeStamp, IEquatable<Person>
{
public string name { get; set; }
public string trigram { get; set; }
public bool active { get; set; }
public eLevel level { get; set; }
public string internal_object_id { get; set; }
public string token { get; set; }
public int unread_objects_count { get; set; }
public int documents_count { get; set; }
public int work_tasks_count { get; set; }
public int review_tasks_count { get; set; }
public bool Equals(Person obj)
{
...
}
public override bool Equals(object obj)
{
...
}
public override int GetHashCode()
{
...
}
}
public class TaskListItem : Task
{
public string taskName
{
get { return this.name + " - " + this.title; }
}
public string DeveloperName
{
get { return Globals.People.Find(x => x.id == this.developer_id).name; }
}
public string ReviewerName
{
get { return Globals.People.Find(x => x.id == this.reviewer_id).name; }
}
}
public class Task : TimeStamp
{
public Task()
{
...
if (Globals.People.Count == 0) Globals.People.Add(new Person { id = 0, name = "DummyUser", level = eLevel.Master });
developer_id = Globals.People.First().id;
reviewer_id = Globals.People.First().id;
...
}
public TaskListItem AsTaskListItem()
{
...
}
public int developer_id { get; set; }
public int reviewer_id { get; set; }
public string name { get; set; }
public string title { get; set; }
...
}
But then as I was learning I found that Static object must not be used to preserve state. So I started searching for an alternative to my implementation. I was able to solve it partially by returning DeveloperName and ReviewerName along with task. So I don't have to use to Static List.
But now I am facing a problem that when I retrieve Tasks from Cache. I am unable to merge it with retrieved data of People.
How Do I Merge it. My above partial solution requires me to retrieve redundant data along with each Task (i.e. Person names with each Task as client has already retrieved all people data).
Complete Code
Please comment for suggestions and improvements.

Categories

Resources