locked
Generics help RRS feed

  • Question

  • User-963208184 posted

    Hi All,

    I am trying to write a generic method that from the type I place in I then want to run the same code, but return a different list of objects.

    Here's what I have so far I'm just trying to get it right for one at the moment

    public List<T> GetNewJoiners<T>(SchemeJoinersReportTypeList reportType,int companyID)
            {
                List<T> result;
                if (reportType == SchemeJoinersReportTypeList.AmberTrust)
                { 
                List<ICurrentSelectionProviderReportItem> selections = _pensionReportItemService.GetByCompany(companyID, null, ProviderReportTypeList.XYZTrust);
                List<ICurrentSelectionProviderReportItem> newJoinerSelections = _reportingFileExportSelectionService.FilterReported(selections);
                result = PopulateNewJoiners(reportType,newJoinerSelections);
                }
                return result;
            }
            private List<T> PopulateNewJoiners<T>(SchemeJoinersReportTypeList reportType,List<ICurrentSelectionProviderReportItem> newJoinerSelections)
            {
                var result = new List<XYZNewJoinerReportItem>();
                XYZNewJoinerReportItem reportItem = null;
                foreach (BasePensionReportItem item in newJoinerSelections)
                {
                    reportItem = new XYZNewJoinerReportItem(item);
                    PopulateItem(reportItem);
                    result.Add(reportItem);
                }
                return result;
            }

    the first issue is that on PopulateNewJoiners errors on return result with 'cant convert List<XYZNewJoinerReportItem> to GenericList<T> and ths filters up to an error on the call to this method



    Wednesday, November 26, 2014 10:15 AM

Answers

  • User-760709272 posted

    If you want to act on specific properties of your generic "T" class you're going to have to use base classes that have the common properties.  What you were probably missing from your code is the "where" clause that tells .net that "T" has to derive from a specific class and isn't just any old object.  Once .net knows that it will let you access the properties of the base class.

    public abstract class MyBaseClass
    {
        public int ID { get; set; }
    }
    
    public class MyClassA : MyBaseClass
    {
        public string PropA { get; set; }
    }
    
    public class MyClassB : MyBaseClass
    {
        public string PropB { get; set; }
    }

    public static List<T> PopulateNewJoiners<T>(int id) where T : MyBaseClass
    {
        List<T> returnData = new List<T>();
        T item = (T)FindById(id);
        if (item != null)
        {
            item.ID = item.ID * 100;
            returnData.Add(item);
        }
    
        return returnData;
    }
    
    public static MyBaseClass FindById(int id)
    {
        if (id > 10)
        {
            return new MyClassA { ID = id, PropA = "A" };
        }
        else
        {
            return new MyClassB { ID = id, PropB = "B" };
        }
    }
    
    static void Main(string[] args)
    {
        // we can use specific classes
        List<MyClassA> dataA = PopulateNewJoiners<MyClassA>(123);
        List<MyClassB> dataB = PopulateNewJoiners<MyClassB>(1);
    
        // or the base class.  dataC will contain something of type ClassB despite the list being of type MyBaseClass
        List<MyBaseClass> dataC = PopulateNewJoiners<MyBaseClass>(10);
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, November 26, 2014 11:35 AM

All replies

  • User-963208184 posted

    Ok,

    Moving on The initial issue I think is further down on PopulateItem, I have an issue getting the properties. I have also changed PopulateNewJoiners Method slightly to Be:

    private List<T> PopulateNewJoiners<T>(SchemeJoinersReportTypeList reportType,List<ICurrentSelectionProviderReportItem> newJoinerSelections)
            {
                List<T> result = new List<T>();
                AmberTrustNewJoinerReportItem reportItem = null;
                foreach (BasePensionReportItem item in newJoinerSelections)
                {
                    reportItem = new AmberTrustNewJoinerReportItem(item);
                    PopulateItem(reportItem);
                    result.Add(reportItem);
                }
                return result;
            }
    private void PopulateItem<T>(T item)
            {
                ProviderAdditionalInformationForCompanyScheme providerAdditionalInfo = _providerAdditionalInformationForCompanySchemeService.Get(item.ProviderID, item.CompanyID, item.BenefitID);
                if (providerAdditionalInfo != null)
                {
                }
            }

    Wednesday, November 26, 2014 10:33 AM
  • User-963208184 posted

    Ok, my populate item now looks like this

    private void PopulateItem<T>(T item)
            {
                Type t = item.GetType();
                
                ProviderAdditionalInformationForCompanyScheme providerAdditionalInfo = _providerAdditionalInformationForCompanySchemeService.Get((int)t.GetProperty("ProviderID").GetValue(t, null), (int)t.GetProperty("CompanyID").GetValue(t, null), (int)t.GetProperty("BenefitID").GetValue(t, null));
                if (providerAdditionalInfo != null)
                {
                }
            }

    So the next Error is in the PopulateNewJoiners method. on result.Add(reportItem).

    basically the overload method has some invalid arguments. ??

    Wednesday, November 26, 2014 10:49 AM
  • User-760709272 posted

    If you want to act on specific properties of your generic "T" class you're going to have to use base classes that have the common properties.  What you were probably missing from your code is the "where" clause that tells .net that "T" has to derive from a specific class and isn't just any old object.  Once .net knows that it will let you access the properties of the base class.

    public abstract class MyBaseClass
    {
        public int ID { get; set; }
    }
    
    public class MyClassA : MyBaseClass
    {
        public string PropA { get; set; }
    }
    
    public class MyClassB : MyBaseClass
    {
        public string PropB { get; set; }
    }

    public static List<T> PopulateNewJoiners<T>(int id) where T : MyBaseClass
    {
        List<T> returnData = new List<T>();
        T item = (T)FindById(id);
        if (item != null)
        {
            item.ID = item.ID * 100;
            returnData.Add(item);
        }
    
        return returnData;
    }
    
    public static MyBaseClass FindById(int id)
    {
        if (id > 10)
        {
            return new MyClassA { ID = id, PropA = "A" };
        }
        else
        {
            return new MyClassB { ID = id, PropB = "B" };
        }
    }
    
    static void Main(string[] args)
    {
        // we can use specific classes
        List<MyClassA> dataA = PopulateNewJoiners<MyClassA>(123);
        List<MyClassB> dataB = PopulateNewJoiners<MyClassB>(1);
    
        // or the base class.  dataC will contain something of type ClassB despite the list being of type MyBaseClass
        List<MyBaseClass> dataC = PopulateNewJoiners<MyBaseClass>(10);
    }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Wednesday, November 26, 2014 11:35 AM