如何在泛型中做到这一点?

时间:2011-06-06 01:22:51

标签: c# c#-4.0 generics

我开始使用泛型并且无法真正找到简单的初学者指南,所以我只是在做试验和错误。

我想转换此

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;
}

是通用的

我开始尝试这个(我还没有遵守它,所以这可能不起作用)

  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;
    }

现在让我感到困惑的是如何将“实体”转换为Task对象,但现在仅将其转换为我需要转换的其他对象,如需要时区的约会。

我无法弄清楚如何让它为我所有不同的物体转换不同的时区。

修改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);

2 个答案:

答案 0 :(得分:9)

如果要访问第一个参数的属性或方法,则需要使用通用接口。无论如何,您不希望在通用方法内部进行转换。如果这些实体派生自公共基类或实现公共接口,则可以使用通用约束并完成它们:

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);
}

答案 1 :(得分:1)

  

现在让我感到困惑的是如何将“实体”转换为Task对象,但现在仅将其转换为我需要转换的其他对象,如需要时区的约会。

如果你使用泛型,你不需要施放。或者换一种说法:你使用泛型的原因是因为你不想投。为了说明这一点,以下是MSDN An Introduction to C# Generics的摘录。

  

由于通用代码不强制对值类型进行装箱和取消装箱,或者对引用类型进行向下转换,因此性能会大大提高。

一般而言,仿制药具有以下优点:

  • 提高效果
  • 强制执行类型安全
  • 可重复使用

如果您需要更具体的示例,请查看(并比较) ArrayList List(T)(在MSDN中搜索它们)。对于add方法, ArrayList 具有以下签名:

public virtual int Add(Object value)

List(T)的相同方法定义为:

public void Add(T item)

因此,您可以看到泛型方法采用任何类型(可重用),并以类型安全的方式处理该类型,而无需强制转换(提高性能)。当然, ArrayList 也是可重用的,但是你需要对它进行强制转换,使它的类型安全性降低,性能更差。

话虽如此,我之前的段落确实存在混淆。虽然您可以使用泛型来处理任何类型,但您也可以实现约束以使通用参数实现特定接口,从而将泛型参数限制为某组类(实现接口的类)。更深入地了解该主题(通用约束)可以在前面提到的C#Generics简介中找到。

至于代码示例,@ Ed S.实际上已经展示了一种可行的方法。 (参考@Ed S的代码示例。)通过使用泛型约束,该参数因此仅限于实现 IEntity 的类,其接口具有 ConvertToUtcTime 方法。