Sending empty class to generic class as default parameter in C# - c#

I have a QueryFilter<TSearchFilter> class (see below). And I created a QueryFilter class that inherits from this class. I'm currently using the QueryFilter without specifying the type, like this:
var queryFilter = new QueryFilter();
To do this, I created a fake EmptySearchFilter class for achieving this. This works perfectly; no problem.
public class QueryFilter<TSearchFilter> where TSearchFilter : class
{
public QueryFilter()
{
SearchFilter = (TSearchFilter)Activator.CreateInstance(typeof(TSearchFilter));
}
public string SortBy { get; set; }
public int PageFirstIndex { get; set; }
public byte PageSize { get; set; }
public TSearchFilter SearchFilter { get; set; }
}
public class QueryFilter : QueryFilter<EmptySearchFilter> { }
public class EmptySearchFilter { }
But, I think that there's probably a way to avoid using this fake class (EmptySearchFilter) by doing something like:
public class QueryFilter : QueryFilter<typeof(Class)>{ }
Is there a way to do this?

You can reverse the inheritance chain like this:
public class QueryFilter
{
public string SortBy { get; set; }
public int PageFirstIndex { get; set; }
public byte PageSize { get; set; }
}
public class QueryFilter<TSearchFilter> : QueryFilter
where TSearchFilter : class, new()
{
public QueryFilter()
{
SearchFilter = new TSearchFilter();
}
public TSearchFilter SearchFilter { get; set; }
}
This way, the QueryFilter does not need to use a fake class.
Also, I've added a new() constraint to get rid of the Activator.CreateInstance call.

Related

How to use Generic Delegate to access Derived Class Members?

Let me preface by saying I am new to coding and C# is my first language
I have a interface:
public interface ITDXInput <TSCContext, TContext, TWaferContainer> : ITDXInput
{
TSCContext SCContext { get; set; }
TContext ToolContext { get; set; }
TWaferContainer WaferContainer { get; set; }
}
This class implements the interface:
public class CIMTDXInput : ITDXInput<CIMSCContext, CIMToolContext, CIMWaferContainer>
{
public CIMWaferContainer WaferContainer { get; set; }
public CIMSCContext SCContext { get; set; }
public CIMToolContext ToolContext { get; set; }
}
The members of this class inherit from the following interfaces:
public class CIMSCContext : ISCContext
{
public string PROCESSING_END_TIME { get; set; }
public string PRODUCT_NAME { get; set; }
public string QUANTITY_IN { get; set; }
public string LOT_OWNER { get; set; }
public string FW_VERSION { get; set; }
}
public class CIMToolContext : IToolContext
{
public string LOT { get; set; }
public string TDX_MULTI_FILES { get; set; }
public string PROCESSING_START_TIME { get; set; }
public string WITHIN_UNIT_AXIS_DIRECTION { get; set; }
}
public class CIMWaferContainer : IWaferContainer
{
public CIMWaferContext WaferContext = new CIMWaferContext();
public List<CIMWaferImage> ImageList = new List<CIMWaferImage>();
public List<CIMWaferDieResults> WaferResultList = new List<CIMWaferDieResults>();
}
I have a delegate handling class:
public class KlarfTemplateDelegateHandler
{
public static Dictionary<string, Delegate> HandlerMap = new Dictionary<string, Delegate>();
public static Dictionary<string, Delegate> DefectListHandlerMap = new Dictionary<string, Delegate>();
delegate string TemplateDelegate<T,U,V>(ITDXInput<T, U, V> cimInput);
delegate string DefectListTemplateDelegate(CIMTDXInput cimInput, List<CIMKlarfDefectList> list);
static KlarfTemplateDelegateHandler()
{
HandlerMap["#DATA.TOOL_CONTEXT.PROCESSING_END_TIME_DATE#"] = new TemplateDelegate<ISCContext,IToolContext, IWaferContainer>(ProcessEndDate);
HandlerMap["#DATA.TOOL_CONTEXT.PROCESSING_END_TIME_TIME#"] = new TemplateDelegate(ProcessEndTime);
}
private static string ProcessEndDate<T,U,V>(ITDXInput<T,U,V> cimInput)
{
DateTime dateTime = DateTime.Parse(cimInput.ToolContext.PROCESSING_END_TIME);
//return cimInput.CIMSCContext.PROCESSING_END_TIME.Split(' ')[0];
return dateTime.ToString("MM-dd-yyyy");
}
}
The issue is that for the function ProcessEndDate, it tells me that 'T' does not contain a definition for "PROCESSING_END_TIME_TIME". I tried to replace TSCContext inside ITDXInput with ISCContext as the generic for the ITDXInput's TSCContext but it's localized.
Is there anything I can do to be able to get the function to see that whatever ITDXInput I pass into the ProcessEndDate function will have the PROCESSING_END_TIME_TIME definition?
I am going through this exercise because I would like to reuse that delegatehandler class for other types of TDXInput
One approach would be to constrain the ProcessEndDate method. A minimal example of this would be to have this interface:
public interface ISCContext
{
string PROCESSING_END_TIME { get; set; }
}
with two different classes that implement it:
public class ClassA : ISCContext
{
public string PROCESSING_END_TIME { get; set; } = "A:" + DateTime.UtcNow.ToString();
}
public class ClassB : ISCContext
{
public string PROCESSING_END_TIME { get; set; } = "B:" + DateTime.UtcNow.ToString();
}
To let the compiler know what to expect in a generic method, you would use the keyword where to make an interface constraint. For clarity, I made a new method with only 1 generic argument. You could, of course, have multiple arguments and corresponding constraints to define expectations for T, U and V but this gives you the basic idea.
private static void showProcessingEndTime<T>(T item) where T : ISCContext
{
Console.WriteLine(item.PROCESSING_END_TIME);
}
Here's a Microsoft article explaining the many ways Generic Type Constraints may be used.
Test code
static void Main(string[] args)
{
var a = new ClassA();
showProcessingEndTime(a);
var b = new ClassB();
showProcessingEndTime(b);
}

Interface with a list of interface, how to choose one type implemented by interface

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

Cast concrete type to nested generic base type

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.

Better Search DTO Design

How do I make a generic SearchDTO which can be used as a template for any Search?
It should have any filter and other general information like TotalRecords, Sort Order, Pages, Start Row, etc
public abstract class SearchDTO
{
public object Id { get; set; }
public IList<T> SearchResults { get; set; }
public int PageSize { get; set; }
public int StartRowNo
{
get
{
return (CurrentPage - 1) * PageSize;
}
}
public int CurrentPage { get; set; }
}
And any Search Object looks like.
public class EmployeeSearchDTO:SearchDTO
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
But I get the following error in IList<T> property:
The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?).
How could I specify like returing a List of any objects and I can create other property like
public long TotalRecords
{
get
{
return SearchResults.Count;
}
set;
}
Is there any best approach other than this to solve this?
You need to specify T as type parameter on your class:
public abstract class SearchDTO<T>
Then when you will inherit from it - you should either provide concrete type instead of type parameter:
public class EmployeeSearchDTO : SearchDTO<MyConcreteType>
or successor class should be generic as well:
public class EmployeeSearchDTO<T> : SearchDTO<T>
You need the declaration on the class as well, to know what type T is:
Code for abstract class
public abstract class SearchDTO<T>
{
public object Id { get; set; }
public abstract IList<T> SearchResults { get; set; }
public int PageSize { get; set; }
public int StartRowNo
{
get
{
return (CurrentPage - 1) * PageSize;
}
}
public int CurrentPage { get; set; }
}
IList<T> SearchResults must be declare as abstract and override in inherited class.
Code of EmployeeSearchDTOP
public class EmployeeSearchDTO:SearchDTO<Employee>
{
public override IList<Employee> SearchResults { get; set; }
}
Create Employee class and move FirstName & LastName properties in Employee class.
Employee Class
public class Employee
{
public string FirstName {get; set; }
public string LastName {get;set;}
}
Until and unless there is a specific reason for you to use a abstract class what you want can be achieved by simply using a template class:
public class SearchDTO<T>
{
public object Id { get; set; }
public IList<T> SearchResults { get; set; }
public int PageSize { get; set; }
public int StartRowNo
{
get
{
return (CurrentPage - 1) * PageSize;
}
}
public int CurrentPage { get; set; }
}
For creating object all you need to do is this:
SearchDTO<EmployeeSearchDTO> obj=new SearchDTO<EmployeeSearchDTO>();
And instead of having SearchResults property create a function that would return a list of EmployeeSearchDTO objects, like this:
public IList<T> SearchResults()
{
IList<T> listObj=new List<T>();
//your code here
return listObj;
}

Issue with generics in c#

I have a problem while adding a new class in my existing structure. I am going to explain my problem as much clear as i can
public interface Imust
{
string Name { get; set; }
string File { get; set; }
string RowKey { get; set; }
string Time { get; set; }
string PartitionKey { get; set; }
}
public class TA : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TB : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TC : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class _Table <T> : _Account where T : Imust
{
}
Here the above 3 classes are implemented as Tables and its properties as its columns in my project. Imust interface is implemented in each class because in generic class i put an interface constraint. TableServiceEntity class contains the implementation for RowKey and PartitionKey.And this class is also inherited in all 3 entities.
Problem : Now i have to add a new table in my application. So for this i have to add a new class here which is
public class TD : TableServiceEntity
{
}
I do not want this class to implement the Imust interface because it does not contain these columns. But i have to pass it as a parameter in generic class _Table.Because this new class has different columns but it perform same function which other 3 entities does. Now how will i add this new class while maintaining my existing structur ?
Please suggest me any better solution for this problem ?
EDIT
Yes i can put a constraint TableServiceEntity as a base class. But in generic class _Table there are few function which operate on File property like
public T AccessEntity(string Id = "0", string File = "0")
{
return (from e in ServiceContext.CreateQuery<T>(TableName)
where e.RowKey == Id || e.File == File
select e).FirstOrDefault();
}
If i removed this interface constraint then it shows an error that T does not have a defination for File.
I'd do this... the interface has no sense in your declaration as the more generic type for table is TableServiceEntity
public class _Table <T> : _Account where T : TableServiceEntity
{
}
Split the interface in two:
public interface Ibase
string RowKey { get; set; }
string PartitionKey { get; set; }
}
public interface Imust : Ibase
{
string Name { get; set; }
string File { get; set; }
string Time { get; set; }
}
public class TA : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TB : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class TC : TableServiceEntity, Imust
{
public string Time { get; set; }
public string Name { get; set; }
public string File { get; set; }
}
public class _BaseTable <T> : _Account where T : Ibase
{
}
public class _Table <T> : _BaseTable<T> where T : Imust
{
}
And implement common functionality in _BaseTable and this specific to Time, Name and File in _Table.
It's even more intuitive after and edit you have made to your question. Thos methods in _BaseTable that rely on File, Name or Time can be marked abstract and overriden in _Table.
Updated to reflect posters additional info:
You need to specify a new Interface:
public interface IMust2 {
public string File {get;set;}
public string Rowkey {get;set;
}
Modify IMust to inherit from IMust2
public interface IMust : IMust2
{
public string Name {get;set;}
public string Time {get;set;}
public string PartitoinKey {get;set;}
}
Why not just have _Table be of <TableServiceEntity> type? Obviously, you are breaking your interface, so you can't keep using it as the generic as not every class will be of that interface?
You have 3 classes (TA, TB and TC) that are exactly the same. Why don't you have a single class, though?
For behavior (that is, methods), use a interface. For structure (that is, properties), use inheritance (like at TableServiceEntity).
Make TD inherit from the base class but do not implement the interface.
Change the restriction at _Table to be where T : TableServiceEntity
Regards

Categories