1

This is a very C# basic question but I don't know how to google it, cause I don't know how this classes are called. I want to define a class (called ContactType) which has two objects: ContactType.Internal & ContactType.External. And each of this objects can be instantiated only once during the application, so every time I define the Type property of a contact as ContactType.External or ContactType.Internal, it is a reference to the same object.

Furthermore, this ContactType class, needs to override the method ToString(), so when the object ContactType.Internal needs to be parsed to string it returns "Contact of type Internal", and similar for the External Object.

chincheta73
  • 187
  • 1
  • 22
  • `.Internal`, `.External` can be solved with subclasses and inheritance, instead of "initiating them only once" use a `static` class, to override `ToString()` use `public override`. – devRicher Jan 08 '17 at 12:28
  • You are probably looking for [readonly](http://stackoverflow.com/questions/3917796/how-to-implement-a-read-only-property) properties, but your question isn't that clear. If your `ContactType` is a class, you can also override the ToString method to return your own implementation of it – Icepickle Jan 08 '17 at 12:28
  • 2
    I feel like your terminology is muddled here. Do you intend `ContactType.Internal` and `ContactType.External` to be *properties* within your `ContactType` class? Also, are you looking to create `Internal` and `External` as objects of the same class or different classes? – Ben Cottrell Jan 08 '17 at 12:29
  • I feel that he's trying ask about enumerations, but doesn't know the term. – Zesty Jan 08 '17 at 13:59

3 Answers3

1

If I understand you correctly this basic principle should get you what you want. Important things to note are that the instances are static and can be accessed everywhere, and that the private constructor prevents any other code (barring reflection, you'll never prevent that) creating its own instances of ContactType.

sealed class ContactType
{
    public static ContactType Internal { get; } = new ContactType();
    public static ContactType External { get; } = new ContactType();

    private ContactType()
    {
    }
}

If you want more code involved in initialising the instances you may want to use a static constructor. This would look something like this:

sealed class ContactType
{
    public static ContactType Internal { get; }
    public static ContactType External { get; }

    private ContactType()
    {
    }

    static ContactType()
    {
        // More code can fit here if creating ContactType is complicated
        Internal = new ContactType();
        External = new ContactType(); 
    }
}

The static constructor will run once (right before the class is first used somewhere in your code) and set the static properties.

And here's an implementation that also handles the ToString() functionality:

sealed class ContactType
{
    private readonly string contactTypeName;

    public static ContactType Internal { get; } = new ContactType("Internal");
    public static ContactType External { get; } = new ContactType("External");

    private ContactType(string contactTypeName)
    {
        this.contactTypeName = contactTypeName;
    }

    public override string ToString()
    {
        // Note that these two ways of building this string are equivalent.
        // You may be more familiar with the old commented out way, but C# 6 added this new interpolation syntax.
        // Take your pick between the two, I prefer the interpolation.

        //return "Contact of type " + this.ContactTypeName;
        return $"Contact of type {this.contactTypeName}";
    }
}
Sam
  • 410
  • 2
  • 10
  • `And each of this objects can be instantiated only once during the application`. I believe static inheritance would solve this problem better than properties. – devRicher Jan 08 '17 at 12:31
  • @devRicher Ahh yeah, I don't feel the question is very clear there. If you're going with this basic approach, the concepts here are still relevant though. Those classes would still likely want private constructors and to be assigned to a static property somewhere. – Sam Jan 08 '17 at 12:46
  • I could add details about the .ToString() to this as well, but I don't want to make the examples too messy or confusing. The basic principle would be to pass an argument to the constructor identifying the instance, store that in a field, then use it to determine what to return from .ToString(). Let me know if you want a full example of that. – Sam Jan 08 '17 at 12:50
  • I mean, I am not the question author, I can only suggest! ;) But yeah, I would suggest mentioning the `override` keyword there. – devRicher Jan 08 '17 at 12:51
  • Also worth noting is that @john-wu is very much correct that dependency injection is often the better option here, but that adds a lot of complexity and likely requires project wide changes, my answer is just keeping things simple for now, John's answer is how I would choose to architect my own project. – Sam Jan 08 '17 at 12:53
  • @devRicher Good point, I'll throw in a full basic implementation at the bottom of the answer with the .ToString() behaviour. – Sam Jan 08 '17 at 12:56
  • Thanks Sam! This is exactly what I meant. Sorry for my terminology, I didn't know how to explain this. Also, what does the "sealed" keyword does in this example? – chincheta73 Jan 08 '17 at 12:58
  • The sealed keyword prevents anyone from creating any classes that inherit from this class. Interestingly here it's actually not needed because if you tried to inherit from it the the new class wouldn't be able to access the private constructor, but it's nice to have it anyway because it makes it really obvious that it can't be inherited. – Sam Jan 08 '17 at 13:06
  • @chincheta73 Would you like a full example with the ToString() implementation, or is this fine as is? – Sam Jan 08 '17 at 13:07
  • Yes please. That would be great! Thanks!! – chincheta73 Jan 08 '17 at 13:08
  • I added the ToString() bit. I haven't tested it properly and I've been awake far too long, but think that's all good, let me know if you have any further issues or questions. – Sam Jan 08 '17 at 13:18
1

Your question wasn't clear, but I think what you're looking for is an enum.

From your description, I understand that your class is Contact. ContactType.External or ContactType.Internal is defined only once. And the property is Type. ToString() should return the static Description of the enum value that is stored in Type.

Class Definition

using System.ComponentModel;

public class Contact
{
    public enum ContactType
    {
        [Description("Contact of type External")]
        External = 1,
        [Description("Contact of type Internal")]
        Internal = 2
    }
    public ContactType Type { get; set; }

    public override string ToString()
    {
        return ((DescriptionAttribute)typeof(ContactType).GetMember(Type.ToString())[0].GetCustomAttributes(typeof(DescriptionAttribute), false)[0]).Description;
    }
}

Usage

    Contact myContact = new Contact();

    myContact.Type = Contact.ContactType.External;
    txtOutput.Text = myContact.ToString();
    //Output: "Contact of type External"

    myContact.Type = Contact.ContactType.Internal;
    txtOutput.Text = myContact.ToString();
    //Output: "Contact of type Internal"
Community
  • 1
  • 1
Zesty
  • 2,922
  • 9
  • 38
  • 69
0

The old way of doing this would have been to use a static variable or a Singleton design pattern. And you can still do it that way. But those static members are terribly difficult to isolate out when writing unit tests.

For this reason, the more modern way to deal with this issue would be use Dependency Injection with something like InstancePerLifetimeScope. That way your object factory will always spit out the same instance of the Internal and External objects no matter how many times the code tries to create them.

Community
  • 1
  • 1
John Wu
  • 50,556
  • 8
  • 44
  • 80