Trying to work out these interfaces - c#

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.

Related

Different parent classes map different subclasses problem

Profile.cs
public class TestConfigProfile : Profile
{
public TestConfigProfile()
{
CreateMap<BaseBO, BaseVO>();
CreateMap<A_BO, A_VO>();
CreateMap<SubBO1, SubVO1>();
}
public class A_BO
{
public BaseBO Sub { get; set; }
}
public class A_VO
{
public BaseVO Sub { get; set; }
}
public class BaseBO
{
public int Id { get; set; }
public string Name { get; set; }
}
public class BaseVO
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SubBO1 : BaseBO
{
public int Size { get; set; }
}
public class SubVO1 : BaseVO
{
public int Size { get; set; }
}
}
test code like this...
public void TestConvert()
{
TestConfigProfile.A_BO bo = new TestConfigProfile.A_BO();
bo.Sub = new TestConfigProfile.SubBO1()
{
Id = 1,
Name = "SubBO1",
Size = 4421
};
TestConfigProfile.A_VO vo = _mapper.Map<TestConfigProfile.A_BO, TestConfigProfile.A_VO>(bo);
}
The result is as follows, but it does not meet my expectations, how can I configure this? Also I don't want to use a parent class.
Successfully mapped to a subclass.
With AutoMapper, mapping inheritance is opt-in.
Therefore, when you map from BaseBO to BaseVO, you need to include the derived mappings.
public TestConfigProfile()
{
CreateMap<BaseBO, BaseVO>()
.Include<SubBO1, SubVO1>(); // Include necessary derived mappings
CreateMap<A_BO, A_VO>();
CreateMap<SubBO1, SubVO1>();
}
See this working example.

Create a Generic list of <T>

I want to create a method that will create a List of generic objects. Is it possible? Something like this:
public class Mtrl
{
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Aa { get; set; }
}
public class Trdr
{
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Address { get; set; }
public string AFM { get; set; }
public string Phone01 { get; set; }
public string Aa { get; set; }
}
And then with a generic class to create my list:
public class GenericClass<T>
{
public List<T> GetData<T>()
{
List<T> myList = new List<T>();
if (typeof(T) == typeof(Trdr))
{
myList.Add(new Trdr());//Error 1: cannot convert from Trdr to 'T'
}
if (typeof(T) == typeof(Mtrl))//Error 2: cannot convert from Mtrl to 'T'
{
myList.Add(new Mtrl());
}
return myList;
}
}
My mistake. I will try to clarify more. The Classes Trdr,Mtrl etc will have many different properties. The Getdata method will take data from a web service via json and i want to create a List of Objects and return it
Something like this:
public List<T> GetData<T>()
{
List<T> myList = new List<T>();
if (typeof(T) == typeof(Trdr))
{
for (int i = 0; i < 100; i++)//fetch data from web api in json format
{
Trdr NewObj = new Trdr();
NewObj.Aa = "...";
NewObj.AFM = "...";
myList.Add(NewObj);
}
}
if (typeof(T) == typeof(Mtrl))
{
for (int i = 0; i < 100; i++)
{
Mtrl NewObj = new Mtrl();
NewObj.Aa = "...";
NewObj.Name = "name ...";
myList.Add(NewObj);
}
}
return myList;
}
}
I suggest extracting an interface (or even a base class):
//TODO: Since you have more than 2 classes, please check the common interface
public interface Idr {
string Id { get; set; }
string Name { get; set; }
string Code { get; set; }
string Aa { get; set; }
}
With all classes of interest implementing it:
public class Mtrl : Idr
{
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Aa { get; set; }
}
public class Trdr : Idr
{
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Aa { get; set; }
public string Address { get; set; }
public string AFM { get; set; }
public string Phone01 { get; set; }
}
Now you can use List<Idr> collection; we want the class (T) that implements Idr to have a parameterless constructor as well (new()):
public class GenericClass<T> where T : Idr, new()
{
public List<T> GetData()
{
List<T> myList = new List<T>() {
new T();
};
return myList;
}
}
Sounds like you are trying to create a new list that contains some initial data, and you need to do this for many different types T.
If Mtrl and Trdr has nothing in common and are handled completely differently, consider simply using different methods to get each type of list:
GetDataMtrl(){
var result = new List<Mtrl>();
result.Add(new Mtrl());
return result;
} // etc
Otherwise what you need is Type Constraints of Generic Parameters, that can tell the compiler more about what T is. Or rather what the different values of T must have in common. For example you can do
public List<T> GetData<T>() where T : new()
{
List<T> myList = new List<T>();
myList.Add(new T());
return myList;
}
To say that for T it has to be possible to do new T(). Then you can say GetData<Trdr>() to get a list that contains a single empty Trdr, as you code might seem to try to do.
Maybe you need to set some default values in the data. I notice the classes has a lot of variables in common. Then you might consider using inheritance to specify this commonality:
public class Mtrl
{
public string Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Aa { get; set; }
}
public class Trdr : Mtrl
{
public string Address { get; set; }
public string AFM { get; set; }
public string Phone01 { get; set; }
}
And then write generic code where T is either of the type Mtrl or its descendant class:
public List<T> GetData<T>() where T : Mtrl
{
List<T> myList = new List<T>();
T MtrlOrTrdr = new T();
MtrlOrTrdr.Id = "my-new-id-";
myList.Add(MtrlOrTrdr);
return myList;
}

How do I create a generic List using abstract class?

I have a Json class "GetAllDevices()". My JSON response consists of an Array/List of objects, where each object has the below common properties.
public class GetAllDevices
{
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("actions")]
public Action[] Actions { get; set; }
public class Action
{
public string _id { get; set; }
public Action_Def action_def { get; set; }
}
public class Action_Def
{
public string _id { get; set; }
public string name { get; set; }
}
}
I want to create 2 generic lists containing all the above properties based on its "type".
lstfoo1 List contains all the properties(_id, name type and actions) where type="foo1". Similarly, lstfoo2 is a List which contains the above properties where type="foo2".
What I have done so far:
string strJson=getJSON();
Foo1 lstfoo1=new Foo1();
Foo2 lstfoo2=new Foo2();
List<Foo1> foo1list= lstfoo1.GetDeviceData(strJson);
List<Foo2> foo2list = lstfoo2.GetDeviceData(strJson);
public class AllFoo1: GetAllDevices
{
}
public class AllFoo2: GetAllDevices
{
}
public abstract class HomeDevices<T>
{
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1{ get; set; }
public List<AllFoo2> lstfoo2{ get; set; }
public abstract List<T> GetDeviceData(string jsonResult);
}
public class Foo1: HomeDevices<AllFoo1>
{
public Foo1()
{
type = "foo1";
}
public override List<AllFoo1> GetDeviceData(string jsonResult)
{
var lst =Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo1>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
public class Foo2: HomeDevices<AllFoo2>
{
public Foo2()
{
type = "foo2";
}
public override List<AllFoo2> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo2>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
My question is, is there an easier way to do this using abstract classes? Can I directly convert my "GetAllDevices" class into an abstract class and inherit it and deserialize into it and create a generic list?
This should help, if I understand your problem correctly. Let me know if you have questions or it doesn't work as you need. I put this together really quickly without testing.
The way the Type property is defined could be improved but I left it as you had it.
public class MyApplication
{
public void DoWork()
{
string json = getJSON();
DeviceTypeOne foo1 = new DeviceTypeOne();
DeviceTypeTwo foo2 = new DeviceTypeTwo();
IList<DeviceTypeOne> foo1Results = foo1.GetDeviceData(json); // calls GetDeviceData extension method
IList<DeviceTypeTwo> foo2Results = foo2.GetDeviceData(json); // calls GetDeviceData extension method
}
}
// implemented GetDeviceData as extension method of DeviceBase, instead of the abstract method within DeviceBase,
// it's slightly cleaner than the abstract method
public static class DeviceExtensions
{
public static IList<T> GetDeviceData<T>(this T device, string jsonResult) where T : DeviceBase
{
IEnumerable<T> deviceDataList = JsonConvert.DeserializeObject<IEnumerable<T>>(jsonResult);
IEnumerable<T> resultList = deviceDataList.Where(x => x.Type.Equals(typeof(T).Name));
return resultList.ToList();
}
}
// abstract base class only used to house common properties and control Type assignment
public abstract class DeviceBase : IDeviceData
{
protected DeviceBase(string type)
{
if(string.IsNullOrEmpty(type)) { throw new ArgumentNullException(nameof(type));}
Type = type; // type's value can only be set by classes that inherit and must be set at construction time
}
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; private set;}
[JsonProperty("actions")]
public DeviceAction[] Actions { get; set; }
}
public class DeviceTypeOne : DeviceBase
{
public DeviceTypeOne() : base(nameof(DeviceTypeOne))
{
}
}
public class DeviceTypeTwo : DeviceBase
{
public DeviceTypeTwo() : base(nameof(DeviceTypeTwo))
{
}
}
// implemented GetAllDevices class as IDeviceData interface
public interface IDeviceData
{
string Id { get; set; }
string Name { get; set; }
string Type { get; }
DeviceAction[] Actions { get; set; }
}
// renamed and relocated class Action to DeviceAction
public class DeviceAction
{
public string Id { get; set; }
public DeviceActionDefinition DeviceActionDefinition { get; set; }
}
// renamed and relocated Action_Def to DeviceActionDefinition
public class DeviceActionDefinition
{
public string Id { get; set; }
public string Name { get; set; }
}
It should be simple enough to move the implementation of method GetDeviceData() to the base class.
For this to work, you will need to add a constraint on T so the compiler knows a bit more about the base type. You will also need to implement a constructor to populate the concrete type's type string you use around. This is a necessary measure to ensure the value is always populated as it is used for comparison in the method in question:
public abstract class HomeDevices<T> where T: GetAllDevices
{
public HomeDevices(string concreteType)
{
type = concreteType;
}
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1 { get; set; }
public List<AllFoo2> lstfoo2 { get; set; }
//This method is now generic and works for both.
public List<T> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
I hope that helps.

Can I create Interface Properties as Generic?

Is there anyway to create such interface which generates properties as generic.
public interface IInterface<T>
{
string nameOf(T)+"_Email" { get; set; } // this won`t compile
string nameOf(T)+"_Phone" { get; set; } // this won`t compile
}
public class Person
{
}
public class Details : IInterface<Person>
{
public string Person_Email { get; set; }
public string Person_Phone { get; set; }
}
I asked above question because my problem was as follow. I want to secure two classes with Interface contract. Then I combine these two classes in a ViewModel. Viewmodel is not really helping because I need these properties on Razor. Please see below.
public interface IPerson
{
string Email { get; set; }
string Phone { get; set; }
}
public interface IHotel
{
string Email { get; set; }
string Phone { get; set; }
}
public class Person : IPerson
{
public string Email { get; set; }
public string Phone { get; set; }
}
public class Hotel: IHotel
{
public string Email { get; set; }
public string Phone { get; set; }
}
public class ViewModel1 : IPerson, IHotel
{
//
// This is missing either Person or Hotel details
//
public string Email { get ; set ; }
public string Phone { get ; set ; }
}
public class ViewModel2 : IPerson, IHotel
{
//
// This is ok but PUBLIC modifier is not allowed, I cannot use.
//
string IPerson.Email { get ; set ; } // public modifier not allowed
string IHotel.Email { get ; set ; } // public modifier not allowed
string IPerson.Phone { get ; set ; } // public modifier not allowed
string IHotel.Phone { get ; set ; } // public modifier not allowed
}
No. It is not possible to dynamically modify the names of interface members with a class level generic argument.
Generics are designed to enable you to re-use the same functionality regardless of which generic type is specified. This is only possible if the interface remains consistent.
Consider this dilemma for example:
public class Foo<T>
{
public string GetPhone(IInterface<T> bar)
{
// how would I know what method to call on foo here?
return bar.????_Phone;
}
}
Below is an example of how you can have generic properties in an interface. You need a base class to translate for you and to bind the type you are looking for
public interface IInterface<T> where T : Contact
{
string Email { get; }
string Phone { get; }
}
public class Person : Contact
{
public string Phone { get; set; }
public string Email { get; set; }
}
public class DetailsBase<T> : IInterface<T> where T : Contact
{
Contact _cont { get; set; }
public string Email { get { return _cont.Email; } }
public string Phone { get { return _cont.Phone; } }
public DetailsBase(Contact cont)
{
_cont = cont;
}
}
public class Contact
{
public string Email { get; set; }
public string Phone { get; set; }
}
public class PersonDetails : DetailsBase<Person>
{
public PersonDetails(Person person) : base(person)
{
}
}

C# template methods for template IEnumerable<T>. Is it possible?

Can anybody help me to solve this problem?
I have a base class:
public class BaseShowFilter {
public int TotalCount { get; set; }
public int FromNo { get; set; }
public int ShowCount { get; set; }
public string SortFieldName { get; set; }
public bool SortAsc { get; set; }
}
and a couple of ChildClasses from this base class. Then I have a few of other classes that store in (for example)
IEnumerable<OtherClassXXX> = ....
And I want to apply some filter to all of them using same method implemented in BaseShowFilter:
For example I need
dstList = srcList.Skip(this.FromNo-1).Take(this.ShowCount);
So I need implement in BaseShowFilter one function that will be accept in parameter IEnumerable and will return also IEnumerable
How can I write it? In pure C++ it will be simple as 1,2,3... but here I don't know how can it be done. Result may be something like this:
public class BaseShowFilter {
public int TotalCount { get; set; }
public int FromNo { get; set; }
public int ShowCount { get; set; }
public string SortFieldName { get; set; }
public bool SortAsc { get; set; }
public T FilterList<T>(T SrcList) where T :IEnumerable<> {
return srcList.Skip(this.FromNo-1).Take(this.ShowCount);
}
}
This is the usual way to do it:
public IEnumerable<T> FilterList<T>(IEnumerable<T> source)
{
return source.Skip(this.FromNo - 1).Take(this.ShowCount);
}

Categories

Resources