Reputation: 6109
I have what I presume must be a common problem. Lets say I have a typical Person Class and I have a Car Class, which has a field/property owner of type Person:
public class Car
{
Person owner;
}
But sometimes I want the car to have no owner. What's the recommended way of dealing with this problem. A Nullable type doesn't work as reference types are already nullable.(Edit: clarification, I meant you cant use Person? owner;)
I could add in a bool field/property: hasOwner, but that seems rather verbose, so I thought of creating a static member none of type Person in the Person class like so:
namespace ConsoleApplication2
{
public class Person
{
public static Person none;
public int age;
static Person()
{
none = new Person();
}
}
public class Car
{
public Person owner;
}
class Program
{
static void Main(string[] args)
{
Car dumped = new Car();
dumped.owner = Person.none;
Console.ReadLine();
}
}
}
This compiles and runs, although I haven't used it in a real application. Then I thought I could make a generic class with a none member as so:
namespace ConsoleApplication2
{
public class NoneMember<T> where T : new()
{
public static T none;
static NoneMember ()
{
none = new T();
}
}
public class Person: NoneMember<Person>
{
}
public class Car
{
public Person owner;
}
class Program
{
static void Main(string[] args)
{
Car dumped = new Car();
dumped.owner = Person.none;
if (dumped.owner == Person.none)
Console.Write("This car has no owner");
Console.ReadLine();
}
}
}
That compiles and runs, although there would be a problem if you wanted to inherit form the person class, with the generic and non generic versons. The thoughts of more experienced c# programmers would be appreciated.
Edit: The problem with using null to represent none is that you can't pass null as a method / constructor parameter. null means value not set, which is different from value is none.
Edit2: I thought I was getting exceptions thrown when I passed null parameters. Not sure what was going on. I don't know if I can reproduce the errors now.
Upvotes: 2
Views: 656
Reputation: 26782
Giving meaning to null
is a valid approach, but generally I find it indeed preferable to have 'richer' support for this situation.
You can always build your own 'nullable type' for reference types. You won't have compiler support, (e.g. no Person?
) but you can get something that gets pretty close.
For example, look at this article from Bart De Smet (look for Option<T>
, the rest of the article is interesting but not in the scope of your question :-))
Upvotes: 0
Reputation: 35894
Yes, static properties/fields is a bit weird when you have inheritance. One framework example is the EventArgs.Empty field which IMO would be nice to have on more specialized classes.
If you expect inheritance from Person and you want to enforce the "this person is nobody" throughout the inherited classes then my recommendation is that you add this concept to the class itself.
If you make a virtual method that returns true or false whether a person is "nobody" or not, your derived classes can extend this check to meet their respective classes' needs:
public class Person
{
public Person()
{
// This constructor will create a "nobody"
}
public Person(string name)
{
// Proper initialization
this.Name = name;
_isNobody = false;
}
public string Name { get; set; }
public virtual bool IsNobody
{
get
{
return String.IsNullOrEmpty(this.Name) == false;
}
}
// TODO: Maybe override Equals/==/GetHashCode to take IsNobody into account
}
One simple example of overridden Person
could be an Employee which is defined to be "Nobody" if either the base class (Person) says it is or if the employee number isn't set:
public class Employee : Person
{
public int EmployeeNumber { get; set; }
public override bool IsNobody
{
return base.IsNobody || EmployeeNumber == -1;
}
}
You could of course combine the above with static fields on your classes, so on your Person class you'd have a
public static readonly Person Nobody = new Person();
and for derived classes (notice use of the new modifier here)
new public static readonly Employee Nobody = new Employee();
I've never seen this approach (with the 'new' modifier) in the wild and would personally be quite reluctant to use it but if it makes sense in your domain it may be an alternative to look at.
Upvotes: 0
Reputation: 1613
The first solution is something that is called in design patterns a null-object. Normally it is done a little different, you create a new class inherited from Person.
public class Person
{
public int age;
}
public class NoPerson : Person
{
}
Then you can validate this with a typeof()
statement
Upvotes: 0
Reputation: 6903
Indeed, why don't null value fit for solve of our problem. If owner is null, It means that owner is not exists at all...
Upvotes: 1
Reputation: 9051
I usually leave it as it is, if Car's owner is null, that means just that - it does not have an owner. There is no need to complicate, if there is value - it has owner, otherwise it does not have (known to system) owner. Exception from this policy is the case when you need to have journaling database, but in that case you usually can have versioned cars and owners and use the same principle.
Upvotes: 1
Reputation: 17038
Both are valid approaches. You'll probably find that most applications simply leave the property as null
and having a special value to indicate an empty value is generally used for value types (TimeSpan.Min
etc).
Upvotes: 1