简体   繁体   中英

How to do this in generics?

I am starting to use generics and been unable to really find the simple beginners guide to them yet so I am just doing trial and error.

I want to convert this

public void CreateTask(Task task, Student student)
{
            Task convertToUtcTime = task.ConvertToUtcTime(student);
            session.Save(convertToUtcTime);
}


public static Task ConvertToUtcTime(this Task task, Student student)
{
    if (student != null)
    {
        TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(student.TimeZoneId);
        task.DueDate = TimeZoneInfo.ConvertTimeToUtc(task.DueDate, info);
    }

    return task;
}

to be generic

I started trying this(I have no complied it yet so this might not even work)

  public void Create<T>(T entity, Student student)
    {
                T convertToUtcTime = entity.ConvertToUtcTime(student);
                session.Save(convertToUtcTime);
    }


  public static T ConvertToUtcTime(this T entity, Student student)
    {
        if (student != null)
        {
            TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(student.TimeZoneId);
            entity.DueDate = TimeZoneInfo.ConvertTimeToUtc(entity.DueDate, info);
        }

        return entity;
    }

Now what confuses the heck out of me is how do I cast "entity" to a Task object but now only that but other objects that I need to convert like an Appointment that needs a timezone.

I just can't figure out how I could make it convert different timeszones for all my different objects.

Edit 2

// also used with nhibernate hence why everything is virtual
    public class Task :IEntity
{
    public virtual int TaskId { get; private set; }
    public virtual DateTime DueDate { get; set; }


    public virtual Task ConvertToUtcTime2(Student student)
    {
        DateTime s = DueDate ;
        // not use to returning "this" but seems only way how to get the object back.
        // I also realized I can do this as well 
        this.ConvertToUtcTime(Student); // So I am still using my extension method and no need to duplicate that code.
        return this;
    }
}

 public interface IEntity
    {
        IEntity ConvertToUtcTime2(Student student);
        // more methods/properties
    }

  public void Create<T>(T entity, Student student) where T: IEntity
        {
            entity.ConvertToUtcTime2(student);
        }

   // call generic method.
   nhibernateRepo.Create(task, student);

You'll need to work through a common interface if you want to access properties or methods of the first parameter. You don't want to be casting around inside of a generic method anyway. If these entities derive from a common base class or implement a common interface you can use a generic constraint and work through them:

public interface IEntity
{
    IEntity ConvertToUtcTime(Student);
    // more methods/properties
}

public void CreateTask<T>(T entity, Student student) where T : IEntity
{
    T convertToUtcTime = entity.ConvertToUtcTime(student);
    session.Save(convertToUtcTime);
}

Now what confuses the heck out of me is how do I cast "entity" to a Task object but now only that but other objects that I need to convert like an Appointment that needs a timezone.

You DO NOT need to cast if you are using generics. Or put this in another way: the reason you are using generics is because you do not want to cast. To illustrate this, below is an excerpt from An Introduction to C# Generics of MSDN.

Because the generic code does not force the boxing and unboxing of value types, or the down casting of reference types, performance is greatly improved.

In general, generics has the following benefits:

  • improves performance
  • enforces type-safety
  • reusable

If you need a more specific example, look at (and compare) ArrayList and List(T) (search for them in MSDN). For the add method, ArrayList has the following signature:

public virtual int Add(Object value)

The same method of List(T) is defined as:

public void Add(T item)

Thus, you can see that a generic method takes in ANY type (reusable), and works on the type in a type-safe manner without the need to cast (improves performance). Of course, ArrayList is also reusable, but you need to do casting on it, making it less type-safe and has worse performance.

Having said that, my previous paragraph actually has a confusion. While you do can make use of generic to work on ANY type, you can also implement a constraint to have the generic parameter implementing a particular interface, thus limiting the generic parameter to a certain set of classes (those that implement the interface). A more in-depth look at the topic (Generic Constraints) can be found in An Introduction to C# Generics mentioned previously.

As for code sample, @Ed S. has actually showed a viable way. (Referring to the code sample of @Ed S.) Through the use of generic constraints, the parameter is thus limited to classes that implement IEntity , an interface of which has a ConvertToUtcTime method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM