In the current system I'm working on I need to have functionality for ammendments.
That being that a user can create an ammendment package and that package contains new version of various domain objects (not structure changes just data changes).
I want to have an "AmmendmentPackage" that contains all of the ammendments that are to be made to various different types of elements.
So far I have
public class AmmendmentPackage : BaseObject
{
public string Name {get;set;}
public string Description { get; set; }
public int MajorVersionNumber { get; set; }
public int MinorVersionNumber { get; set; }
public bool IsGazetted { get; set; }
public AmmendmentPackageState State { get; set; }
}
public class Ammendment<T>
{
public T AmmendedElement{get;set;}
public AmmendmentState State {get;set;}
public ConcurrencyDetails ConcurrencyState { get; set; }
}
How do I go about having the AmmendmentPackage contain number of different Ammentments of various types. I was thinking about using ICollection but then I would have an ICollection<Ammenndment<T>> and I could only have one type of ammendment in the package.
Also was considering using a dictionary but not 100% sure how I would work that in just yet, hopefully I haven't missed something really basic but would appreciate some ideas.
Cheers
This is not possible.
You cannot have a strongly-typed collection that holds different types of objects.
Instead, you should make a non-generic base class or interface and make a collection of those.
You can create a collection of different concrete types that implement the same interface. If you make the interface definition empty, then it can even be applied to any reference type without modifying that type (but you'll have to figure out what operations are available on an AmmendedElement at runtime - I don't recommend this, it is just possible). For example:
using System;
using System.Collections.Generic;
public interface IAnyType { }
public abstract class PackageBase { }
public class Class_1 : IAnyType { public string Class_1_String { get; set; } }
public class Class_2 : IAnyType { public string Class_2_String { get; set; } }
public class AmmendmentPackage : PackageBase
{
public IList<Ammendment<IAnyType>> Ammendments { get; set; }
}
public class Ammendment<T> where T : IAnyType
{
public T AmmendedElement { get; set; }
}
class Program
{
static void Main(string[] args)
{
Ammendment<IAnyType> ammendment_1 = new Ammendment<IAnyType>();
ammendment_1.AmmendedElement = new Class_1();
Ammendment<IAnyType> ammendment_2 = new Ammendment<IAnyType>();
ammendment_2.AmmendedElement = new Class_2();
AmmendmentPackage package = new AmmendmentPackage();
package.Ammendments = new List<Ammendment<IAnyType>>(2);
package.Ammendments.Add(ammendment_1);
package.Ammendments.Add(ammendment_2);
}
}
Related
I have my ResponseDto which includes a simple string property named Answer.
public string Answer { get; set; }
Now, the requirement came such that I could either be getting an answer as a string, or as an array of int.
I decided to create two classes for this:
public class AnswerType {
public string Answer { get; set; }
}
public class OptionAnswerType {
public int[] AnswerOptionIds { get; set; }
}
I could serialize / deserialize it accordingly.
But to still keep a single response property type, I thought about creating an empty base class:
public class BaseAnswerType { }
public class AnswerType : BaseAnswerType {
public string Answer { get; set; }
}
public class OptionAnswerType : BaseAnswerType {
public Guid[] AnswerOptionIds { get; set; }
}
and change my property in ResponseDto to:
public BaseAnswerType Answer { get; set }
through which via run time, I would be returning either of the two classes.
Is this a bad approach? Any alternate would be greatly appreciated.
This is my first question on StackOverflow, so please forgive and tell me if I'm doing something wrong.
Problem:
I write some kind of dictionary connected to DB and text files etc. nothing commercial, just learning. For better explanation it can be English-French.
I want to refactor the code to have possibility of use one "general" method to process entrance for English-French and French-English dictionary model. On the begining i made separate model for each of them(I will paste if necessary) and now i would like to make everything "universal". What I did till i stop:
public interface IWordModel
{
int Id { get; set; }
string Name { get; set; }
string Definition { get; set; }
}
class implementing IWordModel:
public class EnglishWordModel: IWordModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Definition { get; set; } = null;
}
public class FrenchWordModel : IWordModel
{
public int Id { get; set; }
public string Name { get; set; }
public string Definition { get; set; } = null;
}
Interface implementing IWordModel and problematic List of this interface:
public interface IDictionairyModel<T> where T : IWordModel
{
int Id { get; set; }
T BaseWord { get; set; }
List<T> DerivativeWords { get; set; }
}
Class implementing IDicionairyModel
public class EnglishFrenchDictionairyModel<T>: IDictionairyModel where T : IWordModel
{
public int Id { get; set; }
public IWordModel BaseWord { get; set; } = new EnglishWordModel();
public List<IWordModel> DerivativeWords { get; set; } = = new
List<IWordModel>(new List<FrenchWordModel>());
}
public class FrenchDictionairyModel: IDictionairyModel<T> where T : IWordModel
{
public int Id { get; set; }
public IWordModel BaseWord { get; set; } = new FrenchWordModel();
public List<IWordModel> DerivativeWords { get; set; } = = new
List<IWordModel>(new List<EnglishWordModel>());
}
And my Question
How to make that i.e in FrenchDictionairyModel instance we will be able to define BaseWord only as FrenchWordModel and add to DerivativeWords list ONLY EnglishWordModel? I know it have something common with covariance and contrvariance but i dont have idea how to apply this here.
Is it above code have some sense from experienced coder point of view or it's look like OK only in my head? If answer is NO then how it should look like, what pattern should i use?
How to use it properly in other methods? As now i was using i.e
public List<EnglishFrenchDictionairyModel>
CreateEnglishFrenchEntrance(List<EnglishFrenchDictionairyModel> model){
( ... )}
but its already showing "Using generic type requires 1 type arguments".
Thanks and have a Great Day!
It sounds like you need two generic parameters - one to apply to BaseWord and one to apply to DerivativeWords:
public interface IDictionairyModel<T,U>
where T : IWordModel, U : IWordModel
{
int Id { get; set; }
T BaseWord { get; set; }
List<U> DerivativeWords { get; set; }
}
Then define your FrenchDictionaryModel as so:
public class FrenchDictionairyModel:
IDictionairyModel<FrenchWordModel, EnglishWordModel>
{
public int Id { get; set; }
public FrenchWordModel BaseWord { get; set; } = new FrenchWordModel();
public List<EnglishWordModel> DerivativeWords { get; set; } = new List<EnglishWordModel>();
}
Thanks D Stanley! it works fine, just need to add two where clauses for U and T like:
public interface IDictionairyModel<T,U>
where T : IWordModel,
where U : IWordModel {(...)}
But now i have another issue which i would like to implement here.
For example i would like to create some method which will be remove duplicates from List but i want to this to be ONE method for all class which implementing IDictionairyModel
public static List<IDictionairyModel<IWordModel, IWordModel>> RemoveDuplicates(this List<IDictionairyModel<IWordModel, IWordModel>> model)
{
(...) return model;
}
What I need to do to be able to use this extension method on
List<FrenchDictionairyModel> model = new List<FrenchDictionairymodel>();
model.RemoveDuplicates();
As for now it return error.
Should I make FrenchDictionairyModel also generic like:
public class PoznanPolishDictionairyModel<T,U> : IDictionairyModel<PoznanWordModel, PolishWordModel>
where T:IWordModel
where U:IWordModel
??? What is the proper way
Thanks a lot!!!
Have a wonderful Sunday!
Best Regards
Let's say I have nested generic data classes similar to the following:
public class BaseRecordList<TRecord, TUserInfo>
where TRecord : BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual IList<TRecord> Records { get; set; }
public virtual int Limit { get; set; }
}
public class BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
public class BaseUserInfo
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
With 2 concrete versions like so:
// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}
public class Project1Record : BaseRecord<Project1UserInfo>
{
public Guid Version { get; set; }
}
public class Project1UserInfo : BaseUserInfo
{
public string FavouriteFood { get; set; }
}
and
// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
[JsonProperty("allRecords")]
public override IList<Project2Record> Records { get; set; }
}
public class Project2Record : BaseRecord<Project2UserInfo> {}
public class Project2UserInfo : BaseUserInfo
{
[JsonProperty("username")]
public override string Name { get; set; }
}
I'm then happy to have 2 repositories that return Project1RecordList and Project2RecordList respectively, but at some point in my code I find myself needing to be able to handle both of these in one place. I figure that at this point I need to be able to treat both of these types as
BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>
as this is the minimum required to meet the generic constraints, but trying to cast or use "as" throws up errors about not being able to convert.
Is there any way to do this, or even a more sane way to handle this situation without massive amounts of code duplication? If it makes any difference this is for a web app and there are already a large number of data classes, many of which use these nested generics.
What you are talking about is called covariance and MSDN has a great article on this here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
First, create a new interface:
interface IBaseRecord<out TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecord inherit from the new interface:
public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
If done right, this should compile:
IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();
To expand this to the BaseRecordList, create IBaseRecordList:
interface IBaseRecordList<out TRecord, out TUserInfo>
where TRecord : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecordList inherit from that:
public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>
And then use as such:
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();
Once you have that setup, just add whatever properties or functions you need to use generically to the interfaces.
Continuing to develop the API I have mentioned in previous posts, I have come across the following situation:
I need to be able to access a list of responses returned by the
webservice.
Problem is I am unsure how to implement IEnumerable on this class.
...
public class ResponseBodyResponse
{
public ResponseListResponse ResponseList { get; set; }
public class ResponseListResponse
{
public ResponseInfoResponse ResponseInfo { get; set; }
public class ResponseInfoResponse
{
public string RequestId { get; set; }
public string RequestType { get; set; }
public DateTime RequestDate { get; set; }
public string RequestStatus { get; set; }
public string Error { get; set; }
public string Memo { get; set; }
}
public ResponseListResponse()
{
ResponseInfo = new ResponseInfoResponse();
}
}
public ResponseBodyResponse()
{
ResponseList = new ResponseListResponse();
}
...
Before anyone asks I did get a copy of the xsd files, however generating the classes using xsd.exe resulted in a ridiculous mishmash of files with conflicting class names causing over 1000 ambiguous naming errors.
You really should return a concrete collection such as a list or an array from a web service instead of an implementation IEnumerable<T>, even though lists and arrays (and other colections) do implement it. Its not IEnumerable<T> that is the key for the serialization.
Aside, the nested class structure makes your code hard to consume.
Since I'm not sure of your intent with your above code, here is an example
public class Road
{
public Car[] Cars { get; set; } // this can be also `List<Car>`
}
public class Car
{
// stuff
}
I am currently developing a client library for connecting to Newegg using the documentation provided by Newegg and have a question on class design.
In working with various API's ( namely NetSuite and Amazon's MWS ) I come across classes that have are used like this:
recToFulfill.packageList = new ItemFulfillmentPackageList();
recToFulfill.packageList.package = new ItemFulfillmentPackage[ifitemlist.item.Length];
recToFulfill.packageList.package[i] = new ItemFulfillmentPackage();
recToFulfill.packageList.package[i].packageWeightSpecified = true;
recToFulfill.packageList.package[i].packageTrackingNumber = "trackingNumber";
The question I have is: How do I properly design the nested objects like above? I have never had to worry about this previously, so I am unsure on where to look, or start.
The bit I need to figure out looks like this ( taken from the API documentation provided):
<UpdateOrderStatusInfo>
<IsSuccess></IsSuccess>
<Result>
<OrderNumber></OrderNumber>
<SellerID></SellerID>
<OrderStatus></OrderStatus>
</Result>
</UpdateOrderStatusInfo>
All fields are type string, except order number which is an integer.
I have this currently:
public class UpdateOrderStatusInfo
{
public string IsSuccess { get; set; }
public int OrderNumber { get; set; }
public string SellerID { get; set; }
public string OrderStatus { get; set; }
}
But the returned XML Response has Results as a parent node which to me seems like it should be represented within the class itself. Would I just do this?
public UpdateOrderStatusInfo results {get; set;}
If so, where do the child nodes go?
What I need is to be able to say is something like:
UpdateOrderStatusInfo updateInfo = new UpdateOrderStatusInfo();
if(updateInfo.IsSuccess.Equals("true")
{
Console.WriteLine(updateInfo.Results.OrderStatus);
}
Any help, or advice on where to get this information is appreciated.
Easy breezy. If it has no children, it's a scalar property. If it does, it is its own class, and referenced in the parent class accordingly. If it repeats, it's a collection, and is referenced like a class (these are complex type, not primitives). Make sure you initialize them in your constructors).
class Program
{
static void Main(string[] args)
{
var myOrder = new UpdateOrderStatusInfo();
myOrder.IsSuccess = "true";
myOrder.OrderResult.OrderNumber = 1001;
myOrder.OrderResult.OrderStatus = "Pending";
myOrder.OrderResult.SellerID = "69";
}
}
public class UpdateOrderStatusInfo
{
public string IsSuccess { get; set; }
public Result OrderResult { get; set; }
public UpdateOrderStatusInfo()
{
OrderResult = new Result();
}
}
public class Result
{
public int OrderNumber { get; set; }
public string SellerID { get; set; }
public string OrderStatus { get; set; }
}
You need to define the Result as a separate class, called whatever you want, then add a Result property as that type. The Result class can be defined at the namespace level, or, if you are unlikely to use it anywhere else on its own, you can nest the class definition inside the UpdateOrderStatusInfo class:
public class UpdateOrderStatusInfo
{
public class UpdateOrderResult
{
public int OrderNumber { get; set; }
public string SellerID { get; set; }
public string OrderStatus { get; set; }
}
public UpdateOrderStatusInfo()
{
Result = new UpdateOrderResult();
}
public string IsSuccess { get; set; }
public UpdateOrderResult Result { get; set; }
}
The easy way is to use the xsd.exe tool.
The command xsd response.xml will generate the file response.xsd
The command xsd response.xsd /C will generate the file response.cs which contains the classes necessary to serialize/deserialize the xml posted.