-1

I am very new to programming so I was trying to do some work with and got stuck with my problem. Here is my code:

//Properties
private static readonly List<string> category = new List<string> 
{ 
    "Electric", 
    "Household", 
    "Garden", 
    "Miscellaneous" 
};

Category HAS to be "readonly"

// Constructor
public Product(List<string> category)
{
    // this.category shows error that it cannot be accessed with an instance reference; 
    // qualify it with a type name instead
    this.category = category;
}

Also in the default constructor I cannot pass it

// Default Constructor
public Product() : this("Miscellaneous")
{
}

So, how to pass 1 one of strings within the list? Or should I use arrays for this? And how do I print it out later?

class TestProduct
{
    static void Main(string[] args)
    {
        // Assigning correct properties to the product
        Product p1 = new Product(1234567, "Cake", "Miscellaneous", 7.5, 150);
        Console.WriteLine(p1);
        Console.ReadLine();
    }
}

Hope my question is clear.

Niyoko
  • 7,512
  • 4
  • 32
  • 59
Rufat
  • 3
  • 2
  • 1
    Please focus on one question at a time, makes it much easier to write up good answers to it. It sounds to me as though you shouldn't use `static`, may I ask why you decided to make the list static but try to set it from an *instance* constructor? – Lasse V. Karlsen Oct 28 '16 at 11:12
  • Ok, I've sold my first problem by removing the "static" keyword. Kinda missed it out in my code. Still don't know how to do the other two. – Rufat Oct 28 '16 at 11:13
  • 3
    This is an unfortunate effect of posting multiple questions together, not only do you risk getting multiple answers that only *together* answer everything, but when you start removing questions you risk also answers now no longer answering *anything*. Please avoid doing this. In other words, post 1 question and if it turns out to be a mistake, delete the question (the delete button). Don't edit out things people have already started answering. – Lasse V. Karlsen Oct 28 '16 at 11:19
  • This was my first question, so I'll try to make my questions more specific next time. Sorry for the problem. – Rufat Oct 28 '16 at 11:40

4 Answers4

3

If you have a fixed set of categories, you can use an enum to store all values.

public enum ProductCategory
{
    Electric,
    Household,
    Garden,
    Miscellaneous
}

You can create a default constructor like this:

public enum ProductCategory
{
    Electric,
    Household,
    Garden,
    Miscellaneous
}

public class Product
{

    public ProductCategory Category { get; }

    public Product(ProductCategory category)
    {
        this.Category = category;
    }

    public Product() : this(ProductCategory.Miscellaneous)
    {
    }

}

static void Main()
{
    Product p1 = new Product();
    Console.WriteLine(p1.Category); // output: Miscellaneous
    Console.ReadKey();
}

If you still want to store your category in a string, you can adapt this example. If you want a fixed list of valid categories, you can check if the category is valid in the constructor.

apk
  • 1,550
  • 1
  • 20
  • 28
  • 1
    Although I like all of the answers but this is an amazing way to store set amount of categories and works really well. Thank you. – Rufat Oct 28 '16 at 11:34
  • So the "correct answer" was to not actually answer your question but instead show you a different way to do it? This answer does not answer the problems described in the question (qualify with type name, default constructor). but instead gives a (good, in all fairness) workaround? – Jerri Kangasniemi Oct 28 '16 at 11:41
  • As I said, should I use arrays instead of list, but I was given another option to solve my problem. – Rufat Oct 28 '16 at 11:46
1

Category HAS to be "readonly"

The problem is not that it is readonly, the reason why you're getting cannot be accessed with an instance reference, qualify it with a type name instead is because you declared the property as static. A static property cannot be accessed as an instance property.

Also in the default constructor I cannot pass it

Yes you can, if you actually pass in the type you declared.

public Product() : this("Miscellaneous") //You're trying to pass in a string
{
}

Can you see why you cannot pass in that string into your base constructor?

public Product(List<string> category) //base constructor takes a List<string>
{
    //stuff
}

You could create a base constructor which actually takes a string:

public Product(string cat)
{
    //Validate that the category passed in is valid, I.E. in your list
    foreach (var item in category)
    {
        if(object.Equals(item, cat))
            break;
        if(object.Equals(item, category.Last()))
            throw new Exception("D'oh! Invalid category");
    }

    //do stuff
}

Something like that. There are probably better ways to validate. Or just make your categories an Enum and use something like Enum.TryParse to validate instead.

Jerri Kangasniemi
  • 633
  • 1
  • 9
  • 23
  • Thank you for your help. I've solved the problem with Enum. – Rufat Oct 28 '16 at 11:40
  • So the "correct answer" was to not actually answer your question but instead show you a different way to do it? This answer does not answer the problems described in the question (qualify with type name, default constructor). but instead gives a (good, in all fairness) workaround? – Jerri Kangasniemi Oct 28 '16 at 11:44
  • @Rufat - Please read [how to ask](http://stackoverflow.com/help/how-to-ask) for future reference. Because the question you asked is not the question that the accepted answer acutally gives an answer to. – Jerri Kangasniemi Oct 28 '16 at 11:46
  • Sorry, if that hurt you in some way, but I am new here, so I will try to improve on my mistakes. – Rufat Oct 28 '16 at 11:50
0

Remove the this qualifier from this.category because you are accessing a static variable which by definition cannot belong to an instance of a class.

Of course this means you'll get a naming collision because the static category cannot be differentiated from the local category - so fall back to using a naming convention like an underscore at the start of the name for the static variable - _category.

You should also rethink why you made the private variable category static - there is no reason for it to be that way.

[...] that sets the Category to Miscellaneous

To solve your main issue - there is no way to do this without writing a new constructor that takes a single string (because you cannot statically define or enforce the length of a List<>, you can only check that programmatically). A good option is to use enums as suggested by @apk, then throw an ArgumentOutOfRangeException from within the chained constructor if the value Miscellaneous isn't passed in. But you should rethink even that strategy - if the value must be Miscellaneous then consider defaulting to that in the chained constructor, don't allow an arbitrary value to be passed in and then test for the one possible correct value.

Community
  • 1
  • 1
slugster
  • 49,403
  • 14
  • 95
  • 145
0

I assumed you don't actually want it to be a static variable (this question might help), as long as you are receiving it in the constructor. Maybe what you want it is to be immutable, which is something quite different.

You can define that constructor this way.

public class Product
{
    private readonly List<string> _categories;

    public Product() : this(new List<string>() { "Miscellanous"})
    {

    }

    public Product(List<string> category)
    {
        _categories = category;
    }
}

Or this way

public class Product
{
    // other code
    public Product()
    {
         categories = new List<string>();
         categories.Add("Miscellanous");
    }
}

Also readonly only forbids changing the reference to the _categories variable. If you want the content to be immutable, then you should have a look at other kind of data structures or simply do it in the code.

Community
  • 1
  • 1
jorgonor
  • 1,679
  • 10
  • 16
  • The static part was indeed a mistake which was left from the previous attempt. Thanks a lot for your help and the article! – Rufat Oct 28 '16 at 11:37