Let's say I have n objects:
class RedSubscriber {
String msisdn {get; set;}
String imsi {get; set;}
...other unique properties specific for RedSubscriber
}
class BlueSubscriber {
String msisdn {get; set;}
String imei {get; set;}
...other unique properties specific for BlueSubscriber
}
class YellowSubscriber {
String msisdn {get; set;}
String iccid {get; set;}
...other unique properties specific for YellowSubscriber
}
And so on, for n objects.
Let's say I want to get the "String msisdn" value of any object, regardless of what color it is. I currently do it using Reflection:
public void getSubscriberMsisdn(Object subscriber){
Type myType = subscriber.GetType();
IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
foreach (PropertyInfo propertyInfo in props)
{
if (propertyInfo == null)
{
continue;
}
var propertyValue = propertyInfo.GetValue(subscriber);
if (propertyValue == null)
{
continue;
}
if(propertyInfo.Name.Equals("msisdn")){
string msisdnValue = propertyValue.ToString();
Debug.WriteLine("The msisdn is: " msisdnValue);
}
}
}
As you can see the code "works", but is absolutely wasteful to call it everytime I need to retrieve some values. Is there a way to access a property (that always maintains the same name and type) that is placed inside different objects, without using the aforementioned reflection method? Any tip will be appreciated.
CodePudding user response:
Yes. Create an interface:
public interface ISubscriber
{
public string msisdn {get; set;};
}
Change your classes to implement the interface, e.g.:
public class RedSubscriber : ISubscriber
{
string msisdn {get; set;}
string imsi {get; set;}
...
}
Create a getSubscriberMsisdn()
method that takes an ISubscriber
:
public void getSubscriberMsisdn(ISubscriber subscriber)
{
Debug.WriteLine("The msisdn is: " subscriber.msisdn);
}
Don't use reflection for polymorphism. Interfaces is a language feature that directly supports polymorphism and supports strong typing at compile time.
CodePudding user response:
In situations like this there are two standard options:
- Interface
- Inheritance
Where to use which not always clear and very often both approaches work.
I think inheritance could work here because your models have a very strong "IS-A" relationship. It could look something like this:
abstract record Subscriber
{
public required string Msisdn { get; init; }
}
record RedSubscriber : Subscriber
{
public required string Imsi { get; init; }
}
record BlueSubscriber : Subscriber
{
public required string Imei { get; init; }
}
And then
void F(Subscriber s)
{
Console.WriteLine(s.Msisdn);
}
Notes:
- I capitalised the names of properties, it's the C# way.
- I took advantage of 'required' 'init' properties to ensure they are never null
- I used records instead of classes because it seems like a good fit: simple classes with value - rather than reference - equality.
- You don't need to use records - just replace 'record' with 'class' in the code above.
BTW. You could remove some of the boiler plate code by using positional records with more concise syntax:
abstract record Subscriber(string Msisdn);
sealed record RedSubscriber(
string Msisdn,
string Imsi)
: Subscriber(Msisdn: Msisdn);
sealed record BlueSubscriber(
string Msisdn,
string Imei)
: Subscriber(Msisdn: Msisdn);