C# generics problem - newing up the generic type with parameters in the constructor

前端 未结 7 704
闹比i
闹比i 2020-12-09 04:02

I am trying to create a generic class which new\'s up an instance of the generic type. As follows:

public class HomepageCarousel : List
            


        
7条回答
  •  粉色の甜心
    2020-12-09 04:54

    Just to add to other answers:

    What you are doing here is basically called projection. You have a List of one type and want to project each item (using a delegate) to a different item type.

    So, a general sequence of operations is actually (using LINQ):

    // get the initial list
    List pageDataList = GetJewellerHomepages();
    
    // project each item using a delegate
    List carouselList =
           pageDataList.Select(t => new ConcreteCarousel(t));
    

    Or, if you are using .Net 2.0, you might write a helper class like:

    public class Project
    {
        public static IEnumerable From
            (IEnumerable source, Func projection)
        {
            foreach (Tsource item in source)
                yield return projection(item);
        }
    }
    

    and then use it like:

    // get the initial list
    List pageDataList = GetJewellerHomepages();
    
    // project each item using a delegate
    List carouselList =
           Project.From(pageDataList, 
               delegate (PageData t) { return new ConcreteCarousel(t); });
    

    I'm not sure how the rest of the code looks like, but I believe that GetInitialCarouselData is not the right place to handle the initialization, especially since it's basically duplicating the projection functionality (which is pretty generic and can be extracted in a separate class, like Project).

    [Edit] Think about the following:

    I believe right now your class has a constructor like this:

    public class HomepageCarousel : List
        where T: IHomepageCarouselItem, new()
    {
        private readonly List jewellerHomepages;
        public class HomepageCarousel(List jewellerHomepages)
        {
            this.jewellerHomepages = jewellerHomepages;
            this.AddRange(GetInitialCarouselData());
        }
    
        // ...
    }
    

    I presume this is the case, because you are accessing a jewellerHomepages field in your method (so I guess you are storing it in ctor).

    There are several problems with this approach.

    • You have a reference to jewellerHomepages which is unneccesary. Your list is a list of IHomepageCarouselItems, so users can simply call the Clear() method and fill it with anything they like. Then you end up with a reference to something you are not using.

    • You could fix that by simply removing the field:

      public class HomepageCarousel(List jewellerHomepages)
      {
          // do not save the reference to jewellerHomepages
          this.AddRange(GetInitialCarouselData(jewellerHomepages));
      }
      

      But what happens if you realize that you might want to initialize it using some other class, different from PageData? Right now, you are creating the list like this:

      HomepageCarousel list =
           new HomepageCarousel(listOfPageData);
      

      Are you leaving yourself any option to instantiate it with anything else one day? Even if you add a new constuctor, your GetInitialCarouselData method is still too specific to use only PageData as a source.

    Conclusion is: Do not use a specific type in your constructor if there is no need for it. Create actual list items (concrete instances) somewhere else.

提交回复
热议问题