I have several classes that look like this. For the sake of simplicity I will show only two.
public interface ITransportation
{
public string Name { get; set; }
public string StringValue { get; set; }
public int IntValue { get; set; }
public List<string> StringListValue { get; set; }
}
public class Car: ITransportation
{
public string Name { get; set; }
public string StringValue { get; set; }
public int IntValue { get; set; } // <- This is used
}
public class Person: ITransportation
{
public string Name { get; set; }
public string StringValue { get; set; } // <- This is used
public int IntValue { get; set; }
}
My goal is get rid of:
public string StringValue { get; set; }
public int IntValue { get; set; }
public List<string> StringListValue { get; set; }
and create only one Value getter/setter. Maybe with a generic datatype.
var transportation = new List<ITransportation>
{
new Car(),
new Person(),
};
foreach (var item in transportation)
{
if (item is Car) // <- this is not practical
{
Console.WriteLine(item.IntValue);
} else if (item is Person)
{
Console.WriteLine(item.StringValue);
}
}
CodePudding user response:
One option would be to make the interface generic, but that would make ITransportation<string>
and ITransportation<int>
different types, and you would not be able to store both in the same list.
If you just want to print the values I would recommend overloading .ToString()
for each type to print whatever value you want. The general recommended method is to delegate any type specific work to the type itself.
If that is not feasible an option would be a type switch, that would at least let you get rid of the properties on the interface.
switch(item ){
Case Car c: Console.WriteLine(c.IntValue); break;
Case Person p: Console.WriteLine(p.StringValue); break;
default: break;
}
You could however have the generic interface derive from the non-generic one, so that any type checking can use the generic interface and not all the actual classes.
switch(item ){
Case ITransport<int> c: Console.WriteLine(c.Value); break;
Case ITransport<string> p: Console.WriteLine(p.Value); break;
default: break;
}
Another alternative would be the visitor pattern. That could let you separate the 'do something with a transportation object' logic from the object itself, while still keeping type-safety. This might be a better option if you find yourself needing to check the types in many places, since the compiler can help you find all the places you need to update when you add another type.