Reputation: 1114
So I have a method that parses an address field coming in and depending on its length, it needs to write to one or more fields(don't ask...Db2 legacy code needed). Currently we have this method implemented for every class that this is required in and I wanted to write a generic method, which I have to some degree accomplished. The problem is that while how we parse out the address field is the same for each object, the property names used are different depending on which class it is.
This then requires me to check the type of object being passed in and then do a double cast (ClassType)(object) to be able to access the properties and set them properly, then do another double cast (T)(object) to return the generic list.
This is inefficient and basically somewhat defeats the purpose of using generics to begin with. Is there a better way to get the same functionality without having to do type checks and double casts to be able to access the class properties?
public List<T> ParseLongNameStreetName<T>(List<T> myList)
{
myList.ForEach(item =>
{
if (item.GetType() == typeof(DP1)) {
DP1 castItem = (DP1)(object)item;
dynamic streetName = ParsedStreetName(castItem.MA1 + " " + castItem.MA2);
castItem.MA1 = streetName.add1;
castItem.MA2 = streetName.add2;
castItem.MA3 = streetName.add3;
item = (T)(object)castItem;
}
else if (item.GetType() == typeof(DI1))
{
DI1 castItem = (DI1)(object)item;
dynamic streetName = ParsedStreetName(castItem.MA1 + " " + castItem.MA2);
castItem.MA1 = streetName.add1;
castItem.MA2 = streetName.add2;
castItem.MA3 = streetName.add3;
item = (T)(object)castItem;
}
else if (item.GetType() == typeof(DW1))
{
DW1 castItem = (DW1)(object)item;
dynamic streetName = ParsedStreetName(castItem.AD1 + " " + castItem.AD2);
castItem.AD1 = streetName.add1;
castItem.AD2 = streetName.add2;
castItem.AD3 = streetName.add3;
item = (T)(object)castItem;
}
});
return myList;
}
private dynamic ParsedStreetName(string address)
{
string add1 = string.Empty;
string add2 = string.Empty;
string add3 = string.Empty;
int addLen = address.Length;
try
{
add1 = addLen > 30 ? address.Substring(0, 30) : address.Substring(0, addLen);
add2 = addLen > 30 ? addLen > 60 ? address.Substring(29, 30) : address.Substring(30, addLen - 30) : "";
add3 = addLen > 60 ? address.Substring(59, addLen - 60) : "";
} catch(Exception ex)
{
Console.WriteLine(ex);
}
return new { add1, add2, add3 };
}
Upvotes: 2
Views: 420
Reputation: 74605
I would probably consider having the addresses descend from a base address entity that has typical names for the properties and/or possibly an overridable method to set the relevant detail. Your parser can treat any variable entity as a base address type and set the properties and the inherited implementation will acquire the specific names:
public class BaseAddress{
protected string _buildingName;
protected string _zipCode;
public void SetAll(string b, string z){ // call this in your parser
_buildingName = b;
_zipCode = z;
}
}
public class WorkAddress:BaseAddress{
public string Factory => _buildingName;
public string PostCode => _zipCode;
}
public class HomeAddress:BaseAddress{
public string HouseName => _buildingName;
public string Zip => _zipCode;
}
It might even make sense to build the parsing routine into the base class, adding overrides only where there is a major difference in operation
In this sense you don't this need to have a generic method that takes all your differing address types when you can instead have methods that take a BaseAddress. I skipped properties for the BaseAddress but it you'll be working with a BaseAddress in that way it would make sense to add them- this was purely in a "my db context expects factory addresses stored in the factory table to have those columns and home addresses to have these columns.."
As an alternative, something like Automapper could be configured to be able to map multiple different types of address objects onto a common one and back, especially if this is a problem where you're crossing the border of application layers
Upvotes: 1
Reputation: 2000
What you're trying to do is assigning addresses to different properties (depends on different types). For it you don't need to use generic type, you just need to create an interface
public interface IAddressAssignable
{
string GetRawAddress();
void AssignAddresses(string add1, string add2, string add3);
}
Make all 3 (DP1, DI1, DWXP111) implements that interface (with different logic (different properties). Then in your ForEach()
myList.ForEach(item =>
{
dynamic streetName = ParsedStreetName(item.GetRawAddress());
item.AssignAddresses(streetName.add1, streetName.add2, streetName.add3);
}
Upvotes: 1