Reputation: 29
I am trying to constrain the parameter of a method call to be one of 2 different classes. I don't know if it is possible or do I have to inherit both classes from a common base class.
Here's what I am using so far but I want to make this type safe:
public static AdoptionApplicationCollection GetApplicationsByApplicant (object applicant)
{
if (applicant.GetType() == typeof(Person))
{
// blah
}
else if (applicant.GetType() == typeof(Organization))
{
// blah
}
// A whole lot more blah
}
I'd like to make applicant a generic of type Person or Organization.
Upvotes: 2
Views: 1890
Reputation: 1289
Adding to my original answer, there is also another way of doing, what you are doing in your question's code, called pattern matching. Instead of using if
s, C#
has a shortcut for both casting and checking types without this ugly typeof()
public static AdoptionApplicationCollection GetApplicationsByApplicant (object applicant)
{
switch(applicant)
{
case Person p:
Console.WriteLine("The person is " + p);
break;
case Organization o:
Console.WriteLine("The organization is " + o);
break;
}
}
In the Person
case, the p
object will be the applicant
automatically casted into the Person
type. In the Organization
case, the o
will be the applicant
automatically casted into the Organization
type. This is a very useful and handy tool, which can make your code much more readable. Just keep in mind, that it's a C# 7.0 functionality, so make sure you are on that version or higher.
Upvotes: 2
Reputation: 1289
If you're really looking for another way of doing that, but don't want these two classes to inherit from a base class, you can create an interface, which would declare all the methods and properties needed in the GetApplicationsByApplicant
method, and make both Person
and Organization
inherit from it.
Upvotes: 1
Reputation: 1553
To solve your problem you have two choice :
1 - Overloading : what you can do here is to overload you method using Person
and Origanzation
public static AdoptionApplicationCollection GetApplicationsByApplicant(Person person)
{
// your process for person
}
public static AdoptionApplicationCollection GetApplicationsByApplicant(Organization organization )
{
// your process for Organization
}
2 - Base Class : you can also create a base class in this way your method which has a base class as type parameter, your method will accept as parameter any object which inherit from your base class.
class Base
{
}
class Person: Base
{
}
class Organization: Base
{
}
public static AdoptionApplicationCollection GetApplicationsByApplicant(Base base)
{
// your process
}
Upvotes: 2
Reputation: 334
If it doesn't have to be a single method, you could create a couple overloads, such that one signature accepts an argument of type Person, and the other accepts an argument of type Organization.
public static AdoptionApplicationCollection GetApplicationsByApplicant(Person person)
{
// blah
}
public static AdoptionApplicationCollection GetApplicationsByApplicant(Organization organization)
{
// blah
}
If it must be a single method, you might consider using the 'OneOf' pattern (I use it frequently when defining protobuf messages). You'd need to create a wrapper class that has both a Person, and Organization member (but only one of them should be non-null, assuming they are both reference types). That code would look something like this:
class Applicant {
Person _person;
Organization _organization;
public Applicant(Person person) {
_person = person;
}
public Applicant(Organization organization) {
_organization = organization;
}
public enum ApplicantCase {
None,
Person,
Organization
}
public Person person { get => _person; }
public Organization organization { get => _organization; }
public ApplicantCase applicant_case {
get {
if (_person != null)
return ApplicantCase.Person;
if (_organization != null)
return ApplicantCase.Organization;
return ApplicantCase.None;
}
}
}
public static AdoptionApplicationCollection GetApplicationsByApplicant(Applicant applicant) {
switch (applicant.applicant_case) {
case Applicant.ApplicantCase.Person:
// blah
break;
case Applicant.ApplicantCase.Organization:
// blah
break;
default:
// bad applicant
break;
}
}
Upvotes: 1
Reputation: 649
It's necessary to make it a single type parameter. To this, you must make them both either inherit from some abstract base class, or make both of them implement an interface. (An empty interface will do.) Then, change the second parameter from type 'object' to the name of the interface or abstract base class.
But really, why are you trying to do it this way? You can just overload the GetApplicationsByApplicant method, like so:
public static AdoptionApplicationCollection GetApplicationsByApplicant(Person applicant)
{
// handle a person
}
public static AdoptionApplicationCollection GetApplicationsByApplicant(Organization submitter)
{
// handle an organization
}
Upvotes: 1