none
When we use generic class in c#? RRS feed

All replies

  • Hi Anas ,

    When we have two or more modules that are identical or similar, and we don't want to write more than one way to achieve them, you can use generics, by writing a method to achieve the functions of multiple modules.

    I hope it will help you.

    Best regards,
    Julia

    MSDN Community Support Please remember to click Mark as Answer ,the responses that resolved your issue, and to click Unmark as Answer if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.





    • Edited by Julia Tuo Friday, February 8, 2019 7:47 AM
    Friday, February 8, 2019 7:40 AM
  • I would encourage you to start with Microsoft documentation

    https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/introduction-to-generics

    A real life example, you are working with a relational database model using Entity Framework. Using generics in this case base actions can be placed into a class that centeralize these actions.

    Below is an example which would be in a shared library.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Threading.Tasks;
    using System.Data.Entity;
    using Revenue.Common.Interfaces;
    using Revenue.Common.Models;
    using System.Reflection;
    
    namespace Revenue.Common.Repositories
    {
        /// <summary>
        /// Overrides IRevenueRepository.
        /// </summary>
        /// <param name="TEntity"></param>
        public abstract class BaseRevenueRepository<TEntity, TContext> : IRevenueRepository<TEntity> 
            where TEntity : class, IBaseEntity
            where TContext : DbContext
        {
    
            private readonly TContext dbContext;
    
            public BaseRevenueRepository()
            {
                dbContext = Activator.CreateInstance<TContext>();
            }
    
            /// <summary>
            /// Return an instance of the DataContext for TEntity
            /// </summary>
            public TContext Context
            {
                get { return dbContext; }
            }
    
            /// <summary>
            /// Return a entity using keys in pKeyArray
            /// </summary>
            /// <param name="pKeyArray"></param>
            /// <returns></returns>
            public async virtual Task<TEntity> GetByKey(object[] pKeyArray)
            {
                return  await dbContext.Set<TEntity>().FindAsync(pKeyArray);
            }
    
            /// <summary>
            /// Build GetUserId and Create base TEntity type class including Id column
            /// </summary>
            /// <returns></returns>
            public virtual IEnumerable<TEntity> GetAll()
            {
                //dbContext.Configuration.ProxyCreationEnabled = false;
                return dbContext.Set<TEntity>().AsEnumerable();
            }
    
            /// <summary>
            /// Add a single item.
            /// </summary>
            /// <param name="pEntity">incoming entity of type TEntity</param>
            /// <returns></returns>
            public virtual async Task<TEntity> Add(TEntity pEntity)
            {
                //This is a post
                dbContext.Set<TEntity>().Add(pEntity);
                await SaveChangesAsync();
                return pEntity;
            }
    
            /// <summary>
            /// Saves changes for items in pList back to the underlying database
            /// </summary>
            /// <param name="pList"></param>
            /// <returns></returns>
            public virtual async Task<IEnumerable<TEntity>> AddList(IEnumerable<TEntity> pList)
            {
                //This is a post
                dbContext.Set<TEntity>().AddRange(pList);
                await SaveChangesAsync();
                return pList;
            }
    
            /// <summary>
            /// Update pEntry to the backend database table
            /// </summary>
            /// <param name="pEntity"></param>
            /// <returns></returns>
            public virtual Task<bool> Update(TEntity pEntity)
            {
                //this is a put
                UpdateEntity(pEntity);
                return SaveChangesAsync();
            }
    
            /// <summary>
            /// Add entry to existing DataContext
            /// </summary>
            /// <param name="pEntity"></param>
            /// <returns></returns>
            private System.Data.Entity.Infrastructure.DbEntityEntry<TEntity> AttachEntity(TEntity pEntity)
            {
                var entry = dbContext.Entry(pEntity);
                dbContext.Set<TEntity>().Attach(pEntity);
                return entry;
            }
    
            /// <summary>
            /// Update the entity with the modified state.
            /// </summary>
            /// <param name="pEntity"></param>
            /// <returns>true if successfull false if error</returns>
            private bool UpdateEntity(TEntity pEntity)
            {
                try
                {
                    var entry = AttachEntity(pEntity);
                    entry.State = EntityState.Modified;
                }
                catch (Exception)
                {
                   return false;
                }           
                return true;
            }
    
            /// <summary>
            /// Loop entity list and update the state of the entity then save.
            /// </summary>
            /// <param name="pList"></param>
            /// <returns>Loop through a list of entities returning true for success, false for failure to complete operation </returns>
            public virtual Task<bool> UpdateList(IEnumerable<TEntity> pList)
            {
                bool updateResult = true;
                 
                // Loop through and exit if any update fails.
                foreach (TEntity aEntity in pList)
                {
                    updateResult= UpdateEntity(aEntity);
                    if (!updateResult)
                    {
                        return Task.FromResult(false);
                    }
                }
    
                return SaveChangesAsync();
            }
    
            /// <summary>
            /// Delete entity by attaching to it and save
            /// </summary>
            /// <param name="pEntity"></param>
            /// <returns>True if successful saved changed for removal of item, False for failure</returns>
            public virtual Task<bool> Delete(TEntity pEntity)
            {
                var entry = AttachEntity(pEntity);
    
                dbContext.Set<TEntity>().Remove(pEntity);
                return SaveChangesAsync();
            }
    
            /// <summary>
            /// Delete a list of entities looping through the delete method and save
            /// </summary>
            /// <param name="pList">Collection of TEntity</param>
            /// <returns>True if successful saved changed for removal of items, False for failure</returns>
            public virtual Task<bool> DeleteList(IEnumerable<TEntity> pList)
            {
                pList.ToList().ForEach( aEntity => {var entry = AttachEntity(aEntity);});
                
                dbContext.Set<TEntity>().RemoveRange(pList);
                        
                return SaveChangesAsync();
            }
    
            /// <summary>
            /// Returns any items of TEntity matching criteria of the Predicate in pPredicate
            /// </summary>
            /// <param name="pPredicate"></param>
            /// <returns></returns>
            public virtual IEnumerable<TEntity> SearchFor(System.Linq.Expressions.Expression<Func<TEntity, bool>> pPredicate)
            {
                return dbContext.Set<TEntity>().Where(pPredicate).AsEnumerable();
            }
    
            /// <summary>
            /// Not implemented GetByUserId, but available to be overridden.
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public virtual IEnumerable<TEntity> GetByUserId(int id)
            {
                throw new NotImplementedException();
            }
    
            /// <summary>
            /// Save changes of entity.
            /// </summary>
            /// <returns>True if successful saved, False for failure</returns>
            public virtual bool SaveChanges()
            {
                //Validation
    
                //Update entities that are views so they do not save. 
                UpdateViewEntityState();
    
                //Save changes
                bool retVal = dbContext.SaveChanges() > 0;
    
                Dispose();
    
                return retVal;
            }
    
            /// <summary>
            /// Dispose of entity
            /// </summary>
            public virtual void Dispose()
            {
                dbContext.Dispose();
            }
    
            /// <summary>
            /// Save changes to the current entity, TEntity to the backend database table
            /// returning result for the task which contains the number of items updated
            /// </summary>
            /// <returns>returns TRUE or FALSE depending on the results of the save.</returns>
            public async Task<bool> SaveChangesAsync()
            {
                //validation!
                bool retVal = false;
    
                try
                {
                    UpdateViewEntityState();
    
                    retVal = await dbContext.SaveChangesAsync() > 0;
    
                    Dispose();
                }
                catch (System.Exception ex)
                {
                    retVal = false;
                }
    
                return retVal;
            }
    
            /// <summary>
            /// Check all entities in the context that are ready to save and mark all items that are views as Unchanged so they do not try and save. 
            /// </summary>
            private void UpdateViewEntityState()
            {
                foreach (var aEntity in dbContext.ChangeTracker.Entries().Where(e => e.State != EntityState.Detached || e.State != EntityState.Unchanged))
                {
                    if (IsEntityAView(aEntity.Entity.GetType(), dbContext))
                        aEntity.State = EntityState.Unchanged;
                }
            }
    
            private bool IsEntityAView(Type type, System.Data.Entity.DbContext context)
            {
    
                var metadata = ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
    
                // Get the part of the model that contains info about the actual CLR types
                var objectItemCollection = ((System.Data.Entity.Core.Metadata.Edm.ObjectItemCollection)metadata.GetItemCollection(System.Data.Entity.Core.Metadata.Edm.DataSpace.OSpace));
                bool mIsView = false;
                try
                {
                    // Get the entity type from the model that maps to the CLR type
                    var entityType = metadata
                            .GetItems<System.Data.Entity.Core.Metadata.Edm.EntityType>(System.Data.Entity.Core.Metadata.Edm.DataSpace.OSpace)
                            .Single(e => objectItemCollection.GetClrType(e) == type);
    
    
                    // Get the entity set that uses this entity type
                    var entitySet = metadata
                        .GetItems<System.Data.Entity.Core.Metadata.Edm.EntityContainer>(System.Data.Entity.Core.Metadata.Edm.DataSpace.CSpace)
                        .Single()
                        .EntitySets
                        .Single(s => s.ElementType.Name == entityType.Name);
    
                    // Find the mapping between conceptual and storage model for this entity set
                    var mapping = metadata.GetItems<System.Data.Entity.Core.Mapping.EntityContainerMapping>(System.Data.Entity.Core.Metadata.Edm.DataSpace.CSSpace)
                            .Single()
                            .EntitySetMappings
                            .Single(s => s.EntitySet == entitySet);
    
                    // Find the storage entity set (table) that the entity is mapped
                    var table = mapping
                        .EntityTypeMappings.Single()
                        .Fragments.Single()
                        .StoreEntitySet;
    
                    // Return the table name from the storage entity set
                    string name = (string)table.MetadataProperties["http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator:Type"].Value ?? table.Name;
                    mIsView = name == "Views";
                }
                catch (System.Exception ex)
                {
                    //Assume if it fails it is not a view
                    mIsView = false;
                }
    
                return mIsView;
            }
        }
    }


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    • Proposed as answer by Stanly Fan Wednesday, February 13, 2019 2:46 AM
    Friday, February 8, 2019 11:08 AM
    Moderator
  • Hi Anas Babar

    Thank you for posting here.

    Based on your issue, you want to know when we use the generic class in c#.

    I make a sample code to explain it.

    public class example
        {
            public string[] test;
            public example(int i)
            {
                this.test = new string [i];
            }
    }
    public class example
        {
            public int[] test;
            public example(int i)
            {
                this.test = new int [i];
            }
        }
    Generic class:
        public class example<T>
        {
            public T[] test;
            public example(int i)
            {
                this.test = new T[i];
            }
    
        }

    You could find the difference between general class and generic class., Generic classes can use T instead of other types of data.

    If we use the same two classes, just the data types are different, we can use generic classes to simplify the code.

    Hope my explanation could be helpful.

    Best regards,

    Jack



    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Monday, February 11, 2019 9:20 AM
    Moderator