Not Understanding Object Instantiation in C#

2019-05-04 17:52发布

问题:

This post goes to a gap in my understanding of C# classes and why they are preferable to static functions.

I am trying to get a List of objects. Each object in the list represents a record in a table. This would be easy to do in a static function.

Using a class, I've been able to do it as follows:

Calling routine:

ListOfBusinesses l = new ListOfBusinesses ();
List<Business> b = l.listBusinesses();

The classes:

 public class Business
 {
    public string Bupk { get; set; }
    public string Bu_name { get; set; }

 }  

 public class ListOfBusinesses
 {
    public List<Business> listBusinesses()
    {

      List<Business> businesses = new List<Business>();
      businesses.Add(new Business("1", "Business Name 1"));
      businesses.Add(new Business("2", "Business Name 2"));

      return businesses;
    }
 }

Couldn't I rewrite the class so that this could be done with one line:

ListOfBusinesses l = new ListOfBusinesses();

It seems to me like the ListofBusinesses class above is nothing but a static function wrapped in a class which has no properties and is only there for the sake of having a class.

I tried:

public class ListOfBusinesses
{
    List<Business> businesses;

    public List<Business> ListOfBusinesses()
    {

      List<Business> businesses = new List<Business>();
      businesses.Add(new Business("1", "Business Name 1"));
      businesses.Add(new Business("2", "Business Name 2"));

      return businesses;
    }
}

But received the compiler error "member names cannot be the same as there enclosing type". Eg, I tried to use a constructor, but am missing something.

Any help would enlighten me in an area I have misunderstood for some time.

Mike Thomas

回答1:

I think you're mixing up the concepts of a static function, a constructor, and a factory method.

Static Function

Definition

This is a method which does not have access (and is not associated with) a this instance of a class.

Example

public class BusinessHelper
{   
    public static List<Business> ListBusinesses()
    {

        List<Business> businesses = new List<Business>();
        businesses.Add(new Business("1", "Business Name 1"));
        businesses.Add(new Business("2", "Business Name 2"));

        return businesses;
    }
}

Usage

Call a static method with the class name, not an instance of the class.

List<Business> businesses = BusinessHelper.ListBusinesses();

Constructor: This is a method which creates the this instance of a class. It does not have a return value and is invoked when an object is instantiated.

Example

public class BusinessList
{   
    public List<Business> TheList;

    public BusinessList()
    {    
        TheList = new List<Business>();
        TheList.Add(new Business("1", "Business Name 1"));
        TheList.Add(new Business("2", "Business Name 2"));   
    }
}

Usage

Create a new instance of the object.

BusinessList myBusinessList = new BusinessList();
businesses = myBusinessList.TheList;

Factory Method

Definition

This is a method that creates an instance of an object, instantiates it in some way, and returns a reference to it.

Example

public class BusinessList
{   
    public List<Business> TheList;

    public static BusinessList BusinessListWithTwoCompanies()
    {
        BusinessList instance = new BusinessList();

        businesses = new List<Business>();
        businesses.Add(new Business("1", "Business Name 1"));
        businesses.Add(new Business("2", "Business Name 2"));

        return instance;
    }
}

Usage

Call the factory method instead of creating a new object.

BusinessList myBusinessList = BusinessList.BusinessListWithTwoCompanies();
businesses = myBusinessList.TheList;

Two things to additionally note:

  1. You declare a businesses field, but proceed to instantiate another variable called businesses in your ListOfBusinesses() method and return it. Nothing will happen to the businesses field. Be careful with variable scoping.

  2. You cannot have a member (field, property, or method) with the same name as the class. This is reserved for the constructor, which has no return type (see above). This is why you are getting the compiler error.



回答2:

Sure. Instead of encapsulating List<Business>, extend it. Then you just have to add things to it in the constructor.

public class ListOfBusinesses : List<Business> {
    public ListOfBusinesses() : base() {
        Add(new Business("1", "Business Name 1"));
        Add(new Business("2", "Business Name 2"));
    }
}

To use it:

List<Business> l = new ListOfBusinesses();


回答3:

Object instantiation is fundamentally the same for all OO languages. Use of classes rather than static functions allows for much more flexibility and ultimately less coding, especially when keeping track of many similar items.

Think of books and libraries.

If you have the book as an object class then you can instantiate it to create lots of books and store them in your library. Every book that you have instatiated is unique. If you have made no changes to it then each instantiated book appears to be a copy of the original (although at a low level each book has a unique serial number). It has the same cover, number of pages and content, BUT you can easily write your name in one copy thus making it different to the rest.

If you made the book a static then although you can't create individual copies, instead you are looking at the same book, but from different points of view. If you write your name in it then your name appears in every view of the book.

I wont post any code as whilst I've been typing this plenty of others have posted code samples for your business objects.



回答4:

You are looking for a factory method instead of a constructor.



回答5:

Your compiler error is because your class name is "ListOfBusinesses" and the method name is also "ListOfBusinesses". This would be fine if it was a constructor, but since you have a return type on it, C# is thinking you meant it to be a method rather than a constructor.

As for getting your list of businesses, why not create a class like this:

public class BusinessService {
   public List<Business> GetBusinesses() {
       // Build and return your list of objects here.
   }
}

Then to use it:

BusinessService service = new BusinessService();
List<Business> businesses = service.GetBusinesses();


回答6:

You're trying to return something different than the class in the constructor

public class ListOfBusinesses
{
    ...

    public List<Business> ListOfBusinesses()
    {
        ...

You can't specify a return type in a constructor, you need:

public ListOfBusinesses()
{
    ...

As Mike Thomas said, you should use a factory instead if that's what you want.



回答7:

The problem is you're using a reserved word (new) used to invoke the constructor of the class.

The semantic of the constructor is to return an instance of the class which is being created and it follows the rule of having no return value and having the same name of the class.

If it wasn't that way, then, if you do any new MyObject ... how would you (or the compiler for that matter) be supposed to know the returning type?



回答8:

Generally speaking, you wouldn't create your ListOfBusinesses class, unless a ListOfBusinesses has some properties that aren't available in a List<Business>. The simplest way of handling this is a static method on the Business class, like so:

public class Business
{
    //Business class methods/properties/fields

    static List<Business> GetList()
    {
        List<Business> businesses = new List<Business>();
        businesses.Add(new Business("1", "Business Name 1"));
        businesses.Add(new Business("2", "Business Name 2"));
        return businesses;
    }
}

While this is the straightforward way, the end result of going down this road is to refactor this method out of the Business class and into an object factory, commonly provided through an ORM framework like NHibernate or Castle Windsor.



回答9:

If i'm not wrong you want to access a db and retrieve a list of objects with a single line call.

First of all you need a DAO class that encapsulates the db access and expose a List method. Inside the DAO you can use NHibernate, Linq2XXX or whatever you want (sample)

public class BusinessItem
{
    public string Code { get; set; }
    public string Description { get; set; }
}

public class BusinessItemsDAO
{
...
    public List<BusinessItem>   List()
    {
        // fake... should retrieve from db
        var list = new List<BusinessItem>();

        // returs the list
        return list;
    }
...
}

your client code could just call

var listOfBusinessItems = new BusinessItemsDAO().List();

returning an IQueryable instead a List could help if you are Linq enabled.



回答10:

As people have said before - your syntax isn't right here. ListOfBusiness() is a constructor and doesn't explicitly return an object. It instead operates on a new instance of ListOfBusiness and should take care of any creation necessary.

That said - if your method to create the List<Business> is simple, there's absolutely no reason it should be part of a static method. You could even define an extension method on List that takes an empty list of that and populates it. This is called the Factory pattern, wherein a method or an instance of an object takes charge of creating new instances.

Where you would want to think about extending ListOfBusiness into an instantiated class is if there are properties or state that needs to be tracked. IF the List<Business> changes each time it is called, or if you need a place to add new Businesses, the ListOfBusiness class might be useful for that.