Handling different representations method [duplicate] - c#

This question already has answers here:
C# generic "where constraint" with "any generic type" definition?
(2 answers)
Closed 9 years ago.
i have a basic DataTag class defined in this way:
public abstract class DataTag<TRaw, TVal>
{
public abstract TVal Value { get; }
public TRaw RawValue { get; set; }
public string Name { get; private set; }
public string Desc { get; private set; }
}
where TRaw is raw data taken from a device, while TVal is the "formatted" value.
So i may have 2 tags from same device:
DataTag t1 = DataTag.Create<ushort,int>();
DataTag t2 = DataTag.Create<ushort[],float()>;
Now i have a class which should contain a list of generic tags
private IEnumerable<DataTag<?,?> _tags();
Of course C# will not accept different kind of generic in the same list, but this is what i would like to achieve. Any tip for that?

One common approach is to declare a non-generic base class. It won't give you strongly-typed access to the data of course, but you can potentially get a plain object version, and the name/description.
public abstract class DataTag
{
public string Name { get; private set; }
public string Description { get; private set; }
public abstract object WeakValue { get; }
public abstract object WeakRawValue { get; }
}
public abstract class DataTag<TRaw, TVal> : DataTag
{
public abstract TVal Value { get; }
public TRaw RawValue { get; set; }
public override object WeakValue { get { return Value; } }
public override object WeakRawValue { get { return RawValue; } }
}
Then your list is just an IEnumerable<DataTag>.
Notes:
I've given different names for the "weakly typed" properties. You could use Value and RawValue, then redeclare them (with new) in the generic type, but that's a pain in the neck in other ways. Avoid the naming collision if you can.
I've only provided a getter for WeakRawValue - you could provide a setter as well, and cast within the generic type, but that feels ugly to me. Heck, I would personally try to get rid of the setters entirely, and pass the values in as constructor arguments, making the type closer to immutable. (It's not going to be "properly" immutable if either of the generic type arguments is itself a mutable type, but it's better than nothing...)

Related

Detect nested type of generic

I'm working on a project which needs to determine the type of an object, take the information from that type and move it to a structure that fits in our database.
For this, I'm using Pattern Matching with a case statement which works fine.
The only thing that I got stuck with is that some types have nested types as well. The information in those nested types is the information that I need.
Take a look at the code below:
public class CallAnswered
{
public string Caller { get; set; }
public MetaDataInformation MetaData{ get; set; }
}
public class CallAbandoned
{
public string ReasonForAbandonment{ get; set; }
public MetaDataInformation MetaData { get; set; }
}
public class MetaDataInformation
{
public DateTime ReceivedAt { get; set; }
public DateTime AnsweredAt { get; set; }
}
public void DetermineType<T>(T callEvent)
{
switch (callEvent)
{
case CallAnswered callAnswered:
case CallAbandoned callAbandoned:
// Somehow, I need to access the "MetaData" property as a type
break;
}
}
Like shown in the code above, I am able to detect the parent type and assign it a variable. Bu I have no clue on how to get the nested MetaDataInformation type.
Does anyone have an idea how this can be resolved?
You do not need a generic type here. By deriving from an abstract base class, you can solve two problems.
You can use the base type instead of the generic type and access all the public members of this base class.
You can add an abstract method in the base class implemented in the two derived classes making the switch statement obsolete.
public abstract class Call
{
public MetaDataInformation MetaData { get; set; }
public abstract void Process();
}
public class CallAnswered : Call
{
public string Caller { get; set; }
public override void Process()
{
// TODO: Do Answer things. You can access MetaData here.
}
}
public class CallAbandoned : Call
{
public string ReasonForAbandonment{ get; set; }
public override void Process()
{
// TODO: Do Abandonment things. You can access MetaData here.
}
}
somewhere else
public void ProcessCalls(Call callEvent)
{
// Replaces switch statement and does the right thing for both types of calls:
callEvent.Process();
}
This is called a polymorphic behavior.
See also:
Polymorphism (Wikikpedia)
Polymorphism (Microsoft Docs)

Can two classes with matching property names of type "int" and "long" be united under one interface?

I have a project with many different auto-generated classes who share many of the same properties. But one of their "shared" properties is declared as an int in some, and a long in others:
public class Book {
int Id { get; set; }
}
public class Movie {
long Id { get; set; }
}
I would like to unite these two classes under a common interface:
public interface Media {
int/long Id;
}
I understand from this question that I can't treat them as the same type, because they aren't.
Based on this question I thought I might declare the field as dynamic in the interface. But this gives me errors because the implementing classes declare the field as int or long, not as dynamic.
The classes are auto-generated from database tables which I do not have the ability to change, so I cannot make the classes all use long or all use int.
Is there an elegant, C-sharpy way to represent both an int and a long in one interface?
There is no way to represent both an int and a long in one interface.
It is like wanted having a car being at the same time a Smart and a Toyota.
I don't know if it will solve your problem but you can create a generic interface:
public interface IMedia<T>
where T : IComparable, IFormattable, IConvertible
{
T Id { get; set; }
}
Usage:
public class Book : IMedia<int>
{
public int Id { get; set; }
}
public class Movie : IMedia<long>
{
public long Id { get; set; }
}
Because there is no true generic polymorphism in C#, it may can't help you... and even with, int (4 bytes) and long (8 bytes) are two different types.
About the lack of true generic polymorphism and the missing diamond operator in C#
Perhaps you can do something like this:
public abstract class ObjectWithId
{
private long _Id;
public int IdAsInt
{
get { return checked((int)_Id); }
set { _Id = (long)value; }
}
public long IdAsLong
{
get { return _Id; }
set { _Id = value; }
}
}
public class Book : ObjectWithId
{
}
public class Movie : ObjectWithId
{
}
You can create an interface if you need:
public interface IObjectWithId
{
public int IdAsInt { get; set; }
public long IdAsLong { get; set; }
}
But you say classes are auto-generated... so can you modify them with interface or abstract parent?
And if you can, why not standardize Ids?
Similar to the previous answer, this is my solution to the issue. I have a DB with both int and long primary keys. I would like to access the Id when passing in a generic object T:
public interface IBaseModel<T>
where T : struct
{
T Id { get; set; }
}
My DTO base:
public abstract class BaseModel<T> : IBaseModel<T>
where T : struct
{
public T Id { get; set; }
}
DTOs with int Ids will then look like this
public class IntModel : BaseModel<int>
{
}
DTOs with long Ids will then look like this
public class LongModel : BaseModel<long>
{
}
Most importantly, when I want to use these DTOs as generic parameters in methods or classes:
static void DoSomething<T>(IBaseModel<T> printMe)
where T : struct
{
Console.WriteLine(printMe.Id);
}
Passing these models are now nice and generic:
IntModel intModel = new IntModel();
intModel.Id = 1;
LongModel longModel = new LongModel();
longModel.Id = 2;
DoSomething(intModel);
DoSomething(longModel);

How to create and set a polymorphic property?

I want to create a class that can take different types of value in a property. I am trying to do this using polymorphism, but I am not still learning how to do this properly, hence my request for advice.
I have a base class and two classes that inherit from it:
public abstract class BaseClass
{
public string Name { get; set; }
public Unit Unit { get; set; }
}
public class DerivedClassFloat : BaseClass
{
public float Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedClassString : BaseClass
{
public string Value { get; set; }
public override string ToString()
{
return Value;
}
}
All is good, I can create a List and add different specialized subclasses. My problem comes when I need change the values of the items in my list:
foreach (var item in ListOfBaseClasses)
{
if(item is DerivedClassFloat)
((DerivedClassFloat) item).Value = float.NaN;
if (item is DerivedClassString)
((DerivedClassString) item).Value = string.Empty;
}
According to what I have read, that looks like a code smell. Is there a better way to access the value property of my derived classes based on the type I am trying to assign?
What about when you want to create the right subclass based on the value?
BaseClass newClass = null;
if (phenotype is DerivedClassFloat)
newClass = new DerivedClassFloat(){Value = 12.2};
if (phenotype is DerivedClassString)
newClass = new DerivedClassString(){Value = "Hello"};
I read about overriding virtual methods, but that works if I want to process the value, not to add or change it … maybe I am missing something?
I should make this more concrete, my apologies, I am not used to post question in this great site.
I need a property that is made of a list of attributes. Each attribute has a name and a value, but the value can be of different types. For example:
public class Organism
{
public string Name { get; set; }
public List<Attribute> Attributes { get; set; }
}
public class Attribute
{
public string AttributeName { get; set; }
public object AttributeValue { get; set; }
}
For a given organism I can have several attributes holding different value types. I wanted to avoid using the object type so that I don’t have to cast to the right type. I though property polymorphism was the solution to handle this case elegantly, but then I found myself using If ..Then which didn’t seem too different from casting in the first place.
If in your particular case you want to reset Value, you can define an abstract ResetValue method in the base class, which will be implemented by the derives classes.
As for your second case, you should check out Creational Design Patterns, and specifically the Factory and Prototype design patterns.
You can use generics to define the type and the implementing subclass will set the Value type to the type constraint:
public abstract class BaseClass<T>
{
public string Name { get; set; }
public Unit Unit { get; set; }
public T Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedFloat : BaseClass<float> {}
public class DerivedString : BaseClass<string> {}
You can use Generics for this particular case:
public abstract class BaseClass<T>
{
public string Name { get; set; }
public Unit Unit { get; set; }
public T Value { get; set; }
}
public class DerivedClassFloat : BaseClass<float>
{
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedClassString : BaseClass<string>
{
public override string ToString()
{
return Value;
}
}
Polymorphic behaviour works on abstraction. Based on what your trying to do, you can reduce code smell to moving as much of your variability in code to base classess.
i would suggest is instead of property write method like as follows. You can something like as follows.
public void setValue(string val, Type type);//move this to your base class
Class MyValue{
private string strVal;
private int intVal;
//constructor
MyValue(string val, Type type){
//check the type enum here and set the values accordingly
}
}
then when set values
foreach (var item in ListOfBaseClasses)
{
item.setValue = MyValue("",Type.INT);
}
I'm not quite sure what you are trying to achieve with this approach - the Value properties are not of the same type, there is also no Value property on the base class which suggests that other types derived from the base class might not have it at all.
If all of your classes require a Value property, then maybe it should be of the most general type object - you could put it onto the base class, but that would require casting the values in the derived classes.
But then you could have a NullObject to represent an absence of value that you could assign to the Value property for every derived class.
You can use the abstract factory pattern. Consider this example:
// Base class
class Button
{
protected Button()
{
}
public string Name { get; set; }
}
// Factory interface
public interface ButtonFactory
{
Button CreateButton();
}
// And the concrete classes
class WindowsButton : Button
{
// ...
}
class WindowsButtonFactory : ButtonFactory
{
public Button CreateButton()
{
return new WindowsButton();
}
}
class MacButton : Button
{
// ...
}
class MacButtonFactory : ButtonFactory
{
public Button CreateButton()
{
return new MacButton();
}
}
Furthermore, you can combine the abstract factory pattern with the strategy pattern to encapsulate the custom behaviors that change with type.

Help refactor my C# code to be more maintainable and to use best coding practices

I have this C# class structure that I would like to refactor to use best coding standards (use interfaces/abstract classes) so it can be more maintainable and reusable. The code as it is right now isn't awful, but it's not ideal.
I have a series of TableItemGroup classes: AccountTableItemGroup, PendingVoteTableItemGroup, and RequestingVoteTableItemGroup. Each TableItemGrup contains a string SectionName and a List for its corresponding TableItem ...as such:
public class AccountTableItemGroup {
public string SectionName { get; set; }
public List<AccountTableItem> Items
{
get { return this._items; }
set { this._items = value; }
}
public List<AccountTableItem> _items = new List<AccountTableItem>();
public AccountTableItemGroup()
{
}
}
In the future there will be many more TableItemGroups and if they are all the same except for the List part, I don't want to have to copy the code and create a new Group every time and make that small change. I know there must be a better way. I would like to keep using the List<> generics so I don't have to cast anything later though.
The other part are the TableItems. I have AccountTableItem, PendingVoteTableItem, and RequestingVoteTableItem. The TableItems are different from each other, but they each share three common strings -- TitleLabel, DetailLabel, and ImageName. But after that, each TableItem may or may not have additional properties or methods along with it ..as such:
public class AccountTableItem
{
public string TitleLabel { get; set; }
public string DetailLabel { get; set; }
public string ImageName { get; set; }
public bool SwitchSetting { get; set; }
public AccountTableItem()
{
}
}
So my question to all of you is, how do I redefine my class structure to allow for as much reuse of code as possible and to use best coding standards?
I was thinking of having an abstract TableItem class or use an interface for the TableItemGroup? I know that using an interface or an abstract class is best for coding standards, but I don't see how it would cut down on the amount of code I will have?
Thanks a lot for any help.
Abstract away your table item adding necessary fields to the interface or base class:
interface ITableItem // or just a simple or abstract class
{
// common fields go here
}
Then can you make your item group generic with a constraint on generic parameter.
public class ItemGroup<T> where T: ITableItem
{
public string SectionName { get; set; }
public List<T> Items { get; private set; }
public ItemGroup()
{
Items = new List<T>();
}
}
Consider using generics to represent the TableItemGroup container, and make a base class for your TableItem, which you can inherit from for specific types of table item. If you inherit directly from List<T>, then you can treat your item group as a collection without having to use the Items property as in your existing design.
There's not much point in using interfaces for these sorts of types. As they stand they are data classes so have no behavior. If they had behavior, using interfaces would make sense as you would then be able to change implementations and so vary behavior.
public class TableItemGroup<T> : List<T> where T : TableItem
{
public TableItemGroup(string sectionName)
{
SectionName = sectionName;
}
public string SectionName { get; private set; }
}
public class TableItem
{
public string TitleLabel { get; set; }
public string DetailLabel { get; set; }
public string ImageName { get; set; }
}
public class AccountTableItem : TableItem
{
public bool SwitchSetting { get; set; }
}
Now that we have a generic TableItemGroup container, you can re-use this for all TableItem types. Having a base class for TableItem again gives you some re-use.
var items = new TableItemGroup<AccountTableItem>("Accounts");
items.Add(new AccountTableItem { SwitchSetting = true });
Unless you want users to be able to add and remove new lists at will, you should make the setter on the items list protected. Users will still be able to add and remove items, but not create a reference to a new list.

Collection of generic types [duplicate]

This question already has answers here:
Collection of generic types
(10 answers)
Closed 7 years ago.
I have an object (form) which contains a collection (.Fields) which I want to contain instances of a generic class (FormField).
The FormField, simply, is defined as such:
public class FormField<T>
{
private Form Form;
public T Value { get; set; }
public string Name { get; set; }
public void Process()
{
// do something
}
public FormField(Form form, string name, T value)
{
this.Name = name;
this.Value = value;
this.Form = form;
}
}
This allows me to have FormField, FormField etc. and that part works great.
What I want is a collection of "Formfields" regardless of the type, but I am forced into defining a type (it seems) such as:
public class Form
{
string Code { get; set; }
string Title { get; set; }
int Year { get; set; }
Guid ClientID { get; set; }
ICollection<FormField<int>> Fields { get; set; }
}
What, I think, I want is an interface that allows me to abstract the type information and thus type the collection as instances of (for exxample) IFormField not FormField<>
But I can't see how to define this without strongly typing the collection in the interface...
Any help (including any alternative solutions!) would be greatly appreciated!
Thanks, Ben
Here's some code to complete Jon's answer:
public interface IFormField
{
string Name { get; set; }
object Value { get; set; }
}
public class FormField<T> : IFormField
{
private Form Form;
public T Value { get; set; }
public string Name { get; set; }
public void Process()
{
// do something
}
public FormField(Form form, string name, T value)
{
this.Name = name;
this.Value = value;
this.Form = form;
}
// Explicit implementation of IFormField.Value
object IFormField.Value
{
get { return this.Value; }
set { this.Value = (T)value; }
}
}
And in your form:
ICollection<IFormField> Fields { get; set; }
Create a non-generic interface or base class, which probably includes everything FormField does except the type-specific bits. Then you can have an ICollection<IFormField>. Obviously you won't be able to use this in a strongly-typed way, in terms of the type of field being used - but you can use all the non-type-specific bits of it (e.g. the name and the form).
Another option (an alternative to Jon's answer) is to apply the adapter pattern, which can be useful when:
you are unable to modify the type, and can thus not define a base-type for it.
or, there is a need to expose 'type-specific bits' (as Jon put it).
When you want to expose type-specific bits, you effectively have to create a non-generic wrapper. A short example:
class NonGenericWrapper<T> : IAdaptor
{
private readonly Adaptee<T> _adaptee;
public NonGenericWrapper(Adaptee<T> adaptee)
{
_adaptee = adaptee;
}
public object Value
{
get { return _adaptee.Value; }
set { _adaptee.Value = (T) value; }
}
}
Implementing this non-generic behavior in a base-type would effectively break the Liskov substitution principle, which is why I prefer the wrapper approach as I also argue in my blog post.

Categories

Resources