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);
}
Related
I have an Generic Abstract Class with some properties like Id, Name, Status, this class inherits several catalogs.
My question is whether it is possible to create a method with a restriction for the catalogs that implement the Abstract Class.
I give some examples so that they understand what I want to do:
public abstract class AbsCatalog<T>
{
public T Id { get; set; }
public string Name { get; set; }
public bool Status { get; set; }
}
These are the classes that implement the abstract class
public class Agent : AbsCatalog<string>
{
public string Office { get; set; }
public Estado Estado { get; set; }
}
public class Models : AbsCatalog<int>
{
public int Year { get; set; }
public string Description { get; set; }
}
The method I want to implement is the following:
List<Agent> Agents = service.GetAgents();
string AgentsDescription = GetDescription<Agent>(Agents);
List<Model> Models = service.GetModels();
string ModelsDescription = GetDescription<Model>(Models);
private string GetDescription<T>(List<T> list) where T : AbsCatalog<T>
{
string description = string.Empty;
if (list.Exists(x => x.Id.ToString() == "0"))
description = "";
else
description = string.Join(", ", list.Where(x => x.Status).Select(x => x.Name).ToArray());
return description;
}
I think the only way is to use two generic type parameters here, for example:
private string GetDescription<T, U>(List<T> list) where T : AbsCatalog<U>
{
//snip
}
And then call it like this:
string AgentsDescription = GetDescription<Agent, string>(Agents);
I'm looking for the best approach of working with different types identically.
I have a web service that goes to specific resource, makes some research and returns an object WebResult, that contains all information about completed operations.
And now I'd like to build a set of different metrics, that will describe all received results. These metrics should provide
different types of data
easy way to collect it
possibility to deserialize it.
Example 1
First I've created separate classes for different metrics
public abstract class AbstractStatistic
{
public string Url { get; set; }
public string ExceptionMessage { get; set; }
public abstract void FillAllMetrics(WebResult result);
}
public class Resource1Statistic : AbstractStatistic
{
public string Title { get; set; }
public string[] Table1_Header { get; set; }
public int Table1_RowCount { get; set; }
public string[] Table2_Header { get; set; }
public int Table2_RowCount { get; set; }
public override void FillAllMetrics(WebResult result)
{
this.Url = result.url;
this.Title = result.data["title"];
this.Table1_Header = result.data["table1.header"].ToObject<string[]>();
//...
}
}
It works, but I'd like to make it in more standard way. One of the reason is that in this approach I have to create separate web form for each metrics.
Example 2
Second working example is universal but redundant: create an abstraction of any datatype
public abstract class AbstractStatistic
{
public string Url { get; set; }
public string Exception { get; set; }
public Dictionary<string, Metric> Metrics { get ;set;}
public abstract void FillAllMetrics(WebResult webResult);
}
public class Metric // Specific class for data
{
public string StringValue { get; set; }
public int? IntegerValue { get; set; }
public string[] ArrayValue { get; set; }
public DateTime? DateTimeValue { get; set; }
}
public class Resource1Statistic : AbstractStatistic
{
public override void FillAllMetrics(WebResult result)
{
this.Metrics.Add("title",
new Metric() { StringValue = result.data["title"].ToString() });
this.Metrics.Add("Table1 Header",
new Metric() { ArrayValue = result.data["table1.header"].ToObject<string[]>() });
//...
}
It works, but I'm sure there is more elegant solution. I don't like to take all these null values in json.
Examples 3
Generic solution (regarding to Adwaenyth)
public abstract class AbstractStatistic
{
public string Url { get; set; }
public string Exception { get; set; }
public List<AbstractMetric> Metrics { get ;set;}
public abstract void FillAllMetrics(WebResult webResult);
}
public abstract class AbstractMetric{}
public class Metric<T> : AbstractMetric
{
public string Name { get; set; }
public T Value { get; set; }
public string Type { get; private set; }
public Metric()
{
this.Type = typeof(T).ToString();
}
}
public class Resource1Statistic : AbstractStatistic
{
public override void FillAllMetrics(WebResult result)
{
this.Metrics.Add(new Metric<string>()
{ Name = "title",
Value = result.data["title"].ToString() });
this.Metrics.Add(new Metric<string[]>()
{ Name = "Table1 Header",
Value = result.data["table1.header"].ToObject<string[]>() });
//...
}
This solution looks nice, but I have to write custom deserializer.
What do you think, is there some good pattern that fits to my task? Or what's the best approach?
I have two classes with some similar fields, some different, and a form that utilizes two different objects depending on what mode it's in (insert/edit).
Instead of using two different objects and if statements checking the form mode, I'd like to have one struct to be hydrated with either of the two objects fields so I can manipulate one object through the page life-cycle. Then separated the struct back to its respective object for insert/updating the DB.
Example of classes:
public partial class SomeClass
{
public Int32 B {get;set;}
public String C {get;set;}
public Boolean D {get;set;}
}
public class SomeOtherClass
{
public Int32 A {get;set;}
public Int32 B {get;set;}
public String C {get;set;}
}
Update with Solution Example:
public interface IInsertable
{
string SharedName { get; set; }
string SharedID { get; set; }
string editedFieldValue { get; set; }
long GetSuperSecreteInfo();
}
internal class InsertableImplementation : IInsertable
{
public string SharedName { get; set; }
public string SharedID { get; set; }
public string editedFieldValue { get; set; }
public long GetSuperSecreteInfo()
{
return -1;
}
}
public interface IUpdateable
{
string SharedName { get; set; }
string SharedID { get; set; }
string updatedFieldValue { get; set; }
Guid GenerateStevesMagicGuid();
}
internal class UpdateableImplementation : IUpdateable
{
public string SharedName { get; set; }
public string SharedID { get; set; }
public string updatedFieldValue { get; set; }
public Guid GenerateStevesMagicGuid()
{
return new Guid();
}
}
public static class WonderTwinFactory
{
public static WonderTwins GenerateWonderTwin(IUpdateable updateable, IInsertable insertable)
{
var wt = new WonderTwins();
// who will win?
wt.SharedID = updateable.SharedID;
wt.SharedID = insertable.SharedID;
// you decide?
wt.SharedName = updateable.SharedName;
wt.editedFieldValue = "stuff";
return wt;
}
}
public class WonderTwins : IInsertable, IUpdateable
{
public string SharedName { get; set; }
public string SharedID { get; set; }
public string editedFieldValue { get; set; }
public long GetSuperSecreteInfo()
{
return 1;
}
public string updatedFieldValue { get; set; }
public Guid GenerateStevesMagicGuid()
{
return new Guid();
}
}
class Program
{
static void Main(string[] args)
{
IUpdateable updateable = new UpdateableImplementation();
IInsertable insertable = new InsertableImplementation();
WonderTwins dualImplementatin = WonderTwinFactory.GenerateWonderTwin(updateable, insertable);
IUpdateable newUpdateable = dualImplementatin as IUpdateable;
IInsertable newInsertable = dualImplementatin as IInsertable;
}
}
Have both classes implement an interface that defines the operations common to each, including both the fields that are shared (assuming the view needs to access them) and also a method to actually perform the operation that they represent (insert/edit).
Other way of doing such things is using C# dynamic object and assign properties directly. It may help to avoid any new type or interface and directly utilizing new dynamic object any time, as much as required.
var newObject = new {
objectOfClass1 = x.prop1,
objectOfClass2 = x.prop2
}
I have a generic class
public class MetadataDifference<T>
{
public T NewMetadata { get; private set; }
public T OldMetadata { get; private set; }
// Other useful properties
public MetadataDifference(T newMetadata, T oldMetadata)
{
NewMetadata = newMetadata;
OldMetadata = oldMetadata;
}
}
I have wrapper class which has a list of MetadataDifference<> as a property.
This doesn't work:
The type or namespace name 'T' could not be found
Code:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<T>> MetadataChanges { get; set; }
// other fields
}
How can I initialize a list of a generic object? Is it possible?
Either enclosing type must be opened generic:
public class DifferencesResult<T>
{
public IEnumerable<MetadataDifference<T>> MetadataChanges { get; set; }
// other fields
}
or you should use methods instead of property:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<T>> GetMetadataChanges<T>();
private void SetMetadataChanges<T>(IEnumerable<MetadataDifference<T>> value)
// other fields
}
In C#, you can't hold generic property in non-generic class.
It depends on what result you want to achieve.
Here you should use a closed type, for example:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<string>> MetadataChanges { get; set; }
// other fields
}
As you cannot have a generic property in a non-generic class.
You could either close it:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<{sometype}>> MetadataChanges { get; set; }
// other fields
}
or use dynamic:
public class DifferencesResult
{
public IEnumerable<MetadataDifference<dynamic>> MetadataChanges { get; set; }
// other fields
}
Define an interface that doesn't have any generic types which MetadataDifference implements to provide untyped access to the underlying object:
public interface IMetadataDifference
{
object NewMetadata { get; }
object OldMetadata { get; }
}
public interface IMetadataDifference<out T> : IMetadataDifference
{
new T NewMetadata { get; }
new T OldMetadata { get; }
}
public class MetadataDifference<T> : IMetadataDifference<T>
{
object IMetadataDifference.NewMetadata { get { return NewMetadata; } }
object IMetadataDifference.OldMetadata { get { return OldMetadata; } }
public T NewMetadata { get; private set; }
public T OldMetadata { get; private set; }
// Other useful properties
public MetadataDifference(T newMetadata, T oldMetadata)
{
NewMetadata = newMetadata;
OldMetadata = oldMetadata;
}
}
public class DifferencesResult
{
public IEnumerable<IMetadataDifference> MetadataChanges { get; set; }
// other fields
}
I have a business model which consists of a parent/child relationship (Identifier/IdentifierValue) and also some snapshot classes which look the same (IdentifierSnapshot/IdentifierValueSnapshot).
I am trying to create an extension method which will work on an enumeration of either Identifier or IdentifierSnapshot, but I just can't work out what to put in the extension method where I have inserted the XXX placeholder.
//Interfaces
public interface IIdentifier<TIdentifierValue>
where TIdentifierValue : IIdentifierValue
{
string Code { get; }
IEnumerable<TIdentifierValue> GetValues();
}
public interface IIdentifierValue
{
string Code { get; }
string Value { get; }
}
//Main classes
public class Identifier : IIdentifier<IdentifierValue>
{
public string Code { get; set; }
public IEnumerable<IdentifierValue> GetValues();
}
public class IdentifierValue : IIdentifierValue
{
public string Code { get; set; }
public string Value { get; set; }
}
//Snapshots
public class IdentifierSnapshot : IIdentifier<IdentifierValueSnapshot>
{
public string Code { get; set; }
public IEnumerable<IdentifierValueSnapshot> GetValues();
}
public class IdentifierValueSnapshot : IIdentifierValue
{
public string Code { get; set; }
public string Value { get; set; }
}
public static IdentifierExtensions
{
public static IEnumerable<XXX> ByCode<XXX>(this IEnumerable<XXX> instance, string code)
{
return instance.Where(x => string.Compare(code, x.Code, true) == 0);
}
}
I think this would do it:
public static IEnumerable<T> ByCode<T,Z>(this IEnumerable<T> instance, string code)
where T:IIdentifier<Z>
where Z:IIdentifierValue