简体   繁体   中英

How to make a generic class implement interface

I have this generic class:

public static class ListBuilder<T> where T : class
{
   public static void Build(XmlElement element, string elementeName, ref List<T> lista)
   {
         XmlNodeList nl = element.GetElementsByTagName(elementeName);

         if (nl != null && nl.Count > 0)
         {
            for (int i = 0; i < nl.Count; i++)
            {
                element = (XmlElement)nl.Item(i);

                T item = (T)Activator.CreateInstance(typeof(T), element);

                if (!lista.Contains(item))
                   lista.Add(item);
            }
         }
    }
}

And I call this method from a lot of parts of my project:

Util.ListBuilder<Alerta>.Build(element, "alerta", ref retorno);

I need to turns all my pages, less coupled, so, I am now converting all my code to be able to receive unit tests.

My first step is to remove coupled declarations, substituting something like that:

private Alerta _alerta;

Into:

private IAlerta _alerta;

So, I will need to transform the call above, into something like that:

Util.ListBuilder<IAlerta>.Build(element, "alerta", ref retorno);

But, when I try to convert my Util method to accept it, like that:

public static class ListBuilder<T> where T : IBaseInterface
{
   public static void Build(XmlElement element, string elementeName, ref List<T> lista)
   {
         XmlNodeList nl = element.GetElementsByTagName(elementeName);

         if (nl != null && nl.Count > 0)
         {
            for (int i = 0; i < nl.Count; i++)
            {
                element = (XmlElement)nl.Item(i);

                T item = (T)Activator.CreateInstance(typeof(T), element);

                if (!lista.Contains(item))
                   lista.Add(item);
            }
         }
    }
}

public interface IBaseInterface
{
}

public interface IAlerta : IBaseInterface
{
    int Id { get; set; }
    string Titulo { get; set; }
    string Mensagem { get; set; }
    DateTime DataAlerta { get; set; }
}

public class Alerta : IAlerta
{
    public int Id { get; set; }
    public string Titulo { get; set; }
    public string Mensagem { get; set; }
    public DateTime DataAlerta { get; set; }
}

The IBaseInterface, is implemented in all my interfaces.

But I am getting an error, saying that I need to have a parameter less constructor. But an interface do not has a constructor.

I dont know if this is the right way to do that, but I need to isolate all my pages classes, removing all classes references/dependencies from the code, changing to interfaces, to permit to implement unit tests, with less dependencies.

What I need to do ?

Thanks.

First of all, your question is incorrect. The code you provided won't give that error as you don't have a new() constraint on the class and you call Activator.CreateInstance with one parameter.

But indeed you can't instantiate an interface anyway. You will need to rethink your design. This method in your ListBuilder class is the culprit:

T item = (T)Activator.CreateInstance(typeof(T), element);

You ask the runtime to instantiate an instance of T , which in your case is IAlerta , so an interface type:

Util.ListBuilder<IAlerta>.Build(element, "alerta", ref retorno);

This means that the generic code above translates in this case to

IAlerta item = (IAlerta)Activator.CreateInstance(typeof(IAlerta), element);

This will indeed always fail, since you can't instantiate an interface.

What you can do:

  • call the Build method with the concrete type as before (why are you introducing the interface exactly? It seems unnecessary since your Alerta class is a simple object)
  • pass a function Func<XElement,T> to instruct the method on how to construct an instance of T , something like this:

     public static class ListBuilder<T> where T : IBaseInterface { public static void Build(XmlElement element, string elementeName, ref List<T> lista, Func<XElement,T> ctor) { XmlNodeList nl = element.GetElementsByTagName(elementeName); if (nl != null && nl.Count > 0) { for (int i = 0; i < nl.Count; i++) { element = (XmlElement)nl.Item(i); T item = ctor(element); if (!lista.Contains(item)) lista.Add(item); } } } } 

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