Link to home
Start Free TrialLog in
Avatar of XTO
XTO

asked on

When to use a generic method versus a method with an interface parameter?

Why would I ever use a generic method when I can just pass in an interface parameter.

Here is an example that uses a generic method:
        internal T DoSomething<T>(T value) where T : IDoIt
        {
            return value;
        }

Open in new window


Here is an example that uses an interface:
        internal IDoIt DoSomething(IDoIt value)
        {
            return value;
        }

Open in new window


   It seems to me that generics are only useful for basic types and for when an interface is not available. When would a programmer want to use one of the examples above instead of another ? Why use the generic method with the IDoIt constraint when he can just use an IDoIt parameter?  
   When is it better to use the generic method, and when is it better to use an interface parameter? Where would a generic parameter in a method be a better choice than an interface parameter in the method, and vice versa? For example, I can imagine a Strategy design pattern using either.


Thanks
Avatar of it_saige
it_saige
Flag of United States of America image

For the sake of an example, reflection would be one reason:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EE_Q28745361
{
	class Program
	{
		static List<IAnimal> animals = new List<IAnimal>()
		{
			new Bear(),
			new Fish(),
			new Cat(),
			new Dog()
		};

		static void Main(string[] args)
		{
			foreach (var animal in animals)
				Console.WriteLine(animal.GetAnimalNoise());
			Console.ReadLine();
		}
	}

	interface IAnimal { }

	class Bear : IAnimal
	{
		public string Noise { get { return "A Bear ROARS!!!"; } }
	}

	class Fish : IAnimal
	{
		public string Noise { get { return "A Fish doesn't make any noise"; } }
	}

	class Dog : IAnimal
	{
		public string Noise { get { return "A Dog BARKS!!!"; } }
	}

	class Cat : IAnimal
	{
		public string Noise { get { return "A Cat MEOWS!!!"; } }
	}

	static class Extensions
	{
		public static string GetAnimalNoise<T>(this T animal) where T : IAnimal
		{
			return (string)animal.GetType().GetProperty("Noise").GetValue(animal, null);
		}
	}
}

Open in new window

Which produces the following output -User generated imageBut really why would you do this becomes the question.  If you want all animals to make a noise, then just define the Noise property (or method) in the interface and have each class handle the implementation.

However, you could see by this that if I wanted, I could remove the noise property from the fish (since it does not make any noise) and modify the extension method to check for a null value; e.g. -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EE_Q28745361
{
	class Program
	{
		static List<IAnimal> animals = new List<IAnimal>()
		{
			new Bear(),
			new Fish(),
			new Cat(),
			new Dog()
		};

		static void Main(string[] args)
		{
			foreach (var animal in animals)
				Console.WriteLine(animal.GetAnimalNoise());
			Console.ReadLine();
		}
	}

	interface IAnimal { }

	class Bear : IAnimal
	{
		public string Noise { get { return "A Bear ROARS!!!"; } }
	}

	class Fish : IAnimal { }

	class Dog : IAnimal
	{
		public string Noise { get { return "A Dog BARKS!!!"; } }
	}

	class Cat : IAnimal
	{
		public string Noise { get { return "A Cat MEOWS!!!"; } }
	}

	static class Extensions
	{
		public static string GetAnimalNoise<T>(this T animal) where T : IAnimal
		{
			return animal.GetType().GetProperty("Noise") != null ? (string)animal.GetType().GetProperty("Noise").GetValue(animal, null) : string.Empty;
		}
	}
}

Open in new window

Which now produces the following output -User generated imageAgain though, this is just silly for this implementation.  

The real solution here would be to use a base class with an overridable Noise method (or property); e.g. -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EE_Q28745361
{
	class Program
	{
		static List<IAnimal> animals = new List<IAnimal>()
		{
			new Bear(),
			new Fish(),
			new Cat(),
			new Dog()
		};

		static void Main(string[] args)
		{
			foreach (var animal in animals)
				Console.WriteLine(animal.GetAnimalNoise());
			Console.ReadLine();
		}
	}

	class IAnimal 
	{
		public virtual string Noise { get { return string.Empty; } }
	}

	class Bear : IAnimal
	{
		public override string Noise { get { return "A Bear ROARS!!!"; } }
	}

	class Fish : IAnimal { }

	class Dog : IAnimal
	{
		public override string Noise { get { return "A Dog BARKS!!!"; } }
	}

	class Cat : IAnimal
	{
		public override string Noise { get { return "A Cat MEOWS!!!"; } }
	}

	static class Extensions
	{
		public static string GetAnimalNoise(this IAnimal animal)
		{
			return animal.Noise;
		}
	}
}

Open in new window

No need for generics, or reflection.

-saige-
Because you might need to pass some elements that do not implement or do not need an interface.

Think of a collection. If you needed to implement an interface to be able to add something to a collection, you would lose the ease that generic collections bring to our set of tools.

Also, when you need to work with structures instead of classes. That is why you often see.n generic methods for basic types. They are all almost all structures. Structures cannot implement an interface.
I should also point out that on the above *real* solution, you wouldn't even need the extension method as the base class implements the noise property and we are not transforming this property.  So to simplify:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace EE_Q28745361
{
	class Program
	{
		static List<IAnimal> animals = new List<IAnimal>()
		{
			new Bear(),
			new Fish(),
			new Cat(),
			new Dog()
		};

		static void Main(string[] args)
		{
			foreach (var animal in animals)
				Console.WriteLine(animal.Noise);
			Console.ReadLine();
		}
	}

	class IAnimal 
	{
		public virtual string Noise { get { return string.Empty; } }
	}

	class Bear : IAnimal
	{
		public override string Noise { get { return "A Bear ROARS!!!"; } }
	}

	class Fish : IAnimal { }

	class Dog : IAnimal
	{
		public override string Noise { get { return "A Dog BARKS!!!"; } }
	}

	class Cat : IAnimal
	{
		public override string Noise { get { return "A Cat MEOWS!!!"; } }
	}
}

Open in new window


-saige-
Avatar of XTO
XTO

ASKER

Hello it_saige,

I'm able to do reflection with interface parameters also. For example,

        public static string GetAnimalNoise(IAnimal animal)
        {
            return animal.GetType().ToString();
        }
True.  But another, oft overlooked (even by me in my initial response) is the capability to constrain to multiple types.

The invoke required pattern


When we start mixing threads into our forms and then attempting to update, modify or otherwise transform elements initialized by one thread from another thread, a common exception is the "cross-thread exception".  The standard pattern to resolve this (save using the BackgroundWorker pattern), is to implement an invoke required pattern.

This pattern has many forms but initially it looks very similar to this:
// Somewhere in the project, usually a form designer file a control called tbName is initialized.
// Now we need to change the contents of this textbox from a background thread.
public delegate void ChangeNameDelegate(string text);
private void ChangeName(string text)
{
	if (tbName.InvokeRequired)
	{
		tbName.Invoke(new ChangeNameDelegate(ChangeName), new [] { text })
	}
	else
	{
		tbName.Text = text;
	}
}

Open in new window

After a while you get tired of copying and pasting the same pattern over and over.  So you modify it to become just a shade more powerful; e.g. -
public delegate void ChangeTextDelegate(TextBox tb, string text);
private void ChangeText(TextBox tb, string text)
{
	if (tb.InvokeRequired)
	{
		tb.Invoke(new ChangeTextDelegate(ChangeText), new [] { tb, text })
	}
	else
	{
		tb.Text = text;
	}
}

Open in new window

And maybe you find out about anonymous delegates; e.g. -
private void ChangeText(TextBox tb, string text)
{
	if (tb.InvokeRequired)
	{
		tb.Invoke(new MethodInvoker(() => { ChangeText(tb, text); }));
	}
	else
	{
		tbName.Text = text;
	}
}

Open in new window

And so on and so forth.  But the inherent problem in the above patterns is you have to design based upon not only the type of *Control*, but also the property to transform and the transformation you want to make, or the *Action* you want to take.

This, then, becomes the generic pattern to use:
public static void HandleInvokeRequired<T>(this T control, Action<T> action) where T : Control, ISynchronizeInvoke
{
	//Check to see is the control is not null
	if (control == null)
		throw new ArgumentNullException(string.Format("Cannot execute {0} on {1}.  {1} is null.", action, control));

	//Check to see if the control is disposed.
	if (control is Control && (control as Control).IsDisposed)
		throw new ObjectDisposedException(string.Format("Cannot execute {0} on {1}.  {1} is disposed.", action, control));

	//Check to see if the handle is created for the control.
	if (control is Control && !(control as Control).IsHandleCreated)
		throw new InvalidOperationException(string.Format("Cannot execute {0} on {1}.  Handle is not created for {1}.", action, control));

	//Check to see if the control's InvokeRequired property is true
	if (control.InvokeRequired)
	{
		try
		{
			//Use Invoke() to invoke your action
			control.Invoke(action, new object[] { control });
		}
		catch (Exception ex)
		{
			throw new Exception(string.Format("Cannot execute {0} on {1}.  {2}.", action, control, ex.Message));
		}
	}
	else
	{
		try
		{
			//Perform the action
			action(control);
		}
		catch (Exception ex)
		{
			throw new Exception(string.Format("Cannot execute {0} on {1}.  {2}.", action, control, ex.Message));
		}
	}
}

Open in new window

So using the above pattern we can now write code like this:
tbName.HandleInvokeRequired(x => x.Text = "Awsome...")

Open in new window

-saige-
A suitable example to explain would be the Nullable<T>. For a int? sum, if the sum is calculated then return an integer or return null. For byte? sum, return a byte value or return null.

You know what the method needs to do, but if the same process can be applied to a variety of types, then you can either, repeat the method with the different types of parameters or you can write a single Generic method and handle the permissible types.

In a School Management application, your WebService can add a Department, Staff, Faculty, Student, Course, etc.,  then accordingly add the Department using the DepartmentClass or staff using the StaffClass or faculty using the FacultyClass, etc.

Since, your WebService can handle generic types, you only need to redo the specific classes and not the generic classes. For example, implementing the same project, for a Coaching Institution, you just change your classes and not the WebService implementation.
Generics cause the compiler to do additional work on your behalf; interfaces have to be coded by you. As a result of this, you can easily create new methods that you can chain together, but that you have only written once--the compiler will take care of creating a specific instance of the method that deals specifically with your type. Think about LINQ:  There is only one implementation of Where (for the sake of argument, assume only one), yet I can where over a List<int>, List<string>, List<Banana>, etc. I don't actually write a Where to handle each case, but the compiler does. Certainly, interfaces could be involved at some point when you are writing a generic, and quite honestly, most of LINQ is based around IEnumerable<T>, but that doesn't mean that generics are any less important.

As with anything, they have their uses, and you should pick the use and paradigm that fits the problem at hand.
Avatar of XTO

ASKER

Thanks everyone for your responses.

James Burger wrote, "Because you might need to pass some elements that do not implement or do not need an interface."
That's similar to my statement in my original post where I wrote, "It seems to me that generics are only useful for basic types and for when an interface is not available."
James' statement that "Structures cannot implement an interface" is also similar to my comment there about using generics when an interface is not available.
Athar13's example with int? sum and byte? sum are also similar to my comment about using generics when an interface is not available.
Kaupfmd's examples with using the List collection with List<int>, List<string>, and List<banana> also illustrate the statement I had already made about using generics with simple types and when an interface is not available.
Besides, from my point of view, using the List example is not fair because List<T> is a pre-built data structure that already implements many useful methods and is not an example of one that I would build myself.

The example of a generic in my question specifically added a constraint to the generic to illustrate that my confusion is over the use of a generic or an interface when an interface is available.
I apologize for the lack of clarity in my question.


it_saige,
It seems to me that I can get the same result with this:
public static void HandleInvokeRequired(this Control control, Action<Control> action)
{
    // Control checks . . . 

    if (control.InvokeRequired)
    {
        try
        {
            control.Invoke(action, new object[] { control });
        }
        catch (Exception)
        { throw; }
    }
}

Open in new window


All,
So, of the two examples in my question, is there any advantage of one over the other. I appreciate your help.
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of XTO

ASKER

As I understand it, the System.Windows.Forms.Control derives from ISyncronizeInvoke, so maybe I could have done something like,

public static void HandleInvokeRequired(this ISyncronizeInvoke control, Action<ISyncronizeInvoke> action) { . . . }

However, to illustrate your point, let's assume that there is a new control type called NewControl that does not implement ISynchronize.
In that case, I can see the value of multiple constraints: a generic allows me to pass in objects derived from more than one type of interface.

So, in the examples in my first post, the generic method could be changed at a future time to this,
        internal T DoSomething<T>(T value) where T : IDoIt, IDoThat
        {
            return value;
        }

Open in new window


But the method with the interface parameter would be stuck as it is unless I changed the interface (which would potentially break many other methods).

So, I now see where it is better to use generic methods.
Are there places where it is not better to use generic methods and use interface methods exclusively?
Avatar of XTO

ASKER

I think I found a perfect example where the generic method with a constraint is better than the method with an interface parameter.

I had these two lines of code which were getting called repeatedly:
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
return jsSerializer.Deserialize<T>(postResult);

Open in new window

So, I put them in their own method:
public T DeserializeMessageToObject<T>(string postResult) where T : IHttpResponseResults
{
   JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
   return jsSerializer.Deserialize<T>(postResult);
}

Open in new window

I was calling the method from this factory method:
public static IHttpResponseResults ParseHttpResponseMsgFactory(
    IHttpResponseResults respResult, 
    HttpResponseMessage respMessage)
{    
    if (respMessage.IsSuccessStatusCode)
    {
        string postResult = respMessage.Content.ReadAsStringAsync().Result;

        if (respResult.GetType() == typeof(AGSToken))
        {
            respResult = JsonHelper.DeserializeMessageToObject<AGSToken>(postResult);         
        }
        if (respResult.GetType() == typeof(AgsServiceStatus))
        {
            respResult = JsonHelper.DeserializeMessageToObject<AgsServiceStatus>(postResult);
        }
    }         

    respResult.StatusCode = respMessage.StatusCode.ToString();
    respResult.ReasonPhrase = respMessage.ReasonPhrase;

    return respResult;
}

Open in new window

But then I thought to myself, what if one day I would want to use an xml serializer instead of a JSON serializer like this:
respResult = XmlHelper.DeserializeMessageToObject<AgsServiceStatus>(postResult);

Open in new window

So, I implemented a IDeserializeToObject interface on my JsonHelper class.
The IDeserializeToObject looks like this:
public interface IDeserializeToObject
{
    T DeserializeMessageToObject<T>(string postResult) where T : IHttpResponseResults;
}

Open in new window

Then I added the IDeserializeToObject as a parameter to my ParseHttpResponseMsgFactory like this,
public static IHttpResponseResults ParseHttpResponseMsgFactory(
    IHttpResponseResults respResult,
    HttpResponseMessage respMessage,
    IDeserializeToObject deserializer)
{
    if (respMessage.IsSuccessStatusCode)
    {
        string postResult = respMessage.Content.ReadAsStringAsync().Result;

        if (respResult.GetType() == typeof(AGSToken))
        {
            respResult = deserializer.DeserializeMessageToObject<AGSToken>(postResult);
        }
        if (respResult.GetType() == typeof(AgsServiceStatus))
        {
            respResult = deserializer.DeserializeMessageToObject<AgsServiceStatus>(postResult);
        }
    }

    respResult.StatusCode = respMessage.StatusCode.ToString();
    respResult.ReasonPhrase = respMessage.ReasonPhrase;

    return respResult;
}

Open in new window

And I call it like this:
AgsToken = HttpHelpers.ParseHttpResponseMsgFactory(
    new AGSToken(), 
    respMessage, 
    new JsonHelper()) as AGSToken;

Open in new window

Or I could call it like this:
AgsServiceStatus serviceStat = HttpHelpers.ParseHttpResponseMsgFactory(
    new AgsServiceStatus(), 
    chkServiceRsp,
    new JsonHelper()) as AgsServiceStatus;

Open in new window

In the future, however, if I wanted to parse with an XML deserializer, I could just add IDeserializeToObject to a XmlHelper class just like I did to the JsonHelper class.

Then I could call my HttpHelpers.ParseHttpResponseMsgFactory like this:
AgsToken = HttpHelpers.ParseHttpResponseMsgFactory(
    new AGSToken(), 
    respMessage, 
    new XmlHelper()) as AGSToken;

Open in new window

Or I could call it like this:
AgsServiceStatus serviceStat = HttpHelpers.ParseHttpResponseMsgFactory(
    new AgsServiceStatus(), 
    chkServiceRsp,
    new XmlHelper()) as AgsServiceStatus;

Open in new window

If I had tried this with an interface, it would not have worked. It would have looked like this:
public IHttpResponseResults DeserializeMessageToObject(string postResult)
{
    JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
    return jsSerializer.Deserialize<IHttpResponseResults>(postResult);
}

Open in new window

And the jsSerializer.Deserialize<T> method would not know what type of IHttpResponseResults to create.
Or you could have written this as such:
public static T ParseHttpResponseMsgFactory<T>(HttpResponseMessage respMessage, IDeserializeToObject deserializer) where T : IHttpResponseResults
{
	T respResult = default(T);
	if (respMessage.IsSuccessStatusCode)
	{
		string postResult = respMessage.Content.ReadAsStringAsync().Result;
		respResult = deserializer.DeserializeMessageToObject<T>(postResult);
	}
	respResult.StatusCode = respMessage.StatusCode.ToString();
	respResult.ReasonPhrase = respMessage.ReasonPhrase;
	return respResult;
}

Open in new window

And now your call becomes:
AgsServiceStatus serviceStatus = HttpHelpers.ParseHttpResponseMsgFactory<AgsServiceStatus>(chkServiceRsp, new JsonHelper());

Open in new window

Or:
AgsToken token = HttpHelpers.ParseHttpResponseMsgFactory<AgsToken>(respMessage, new XmlHelper());

Open in new window

-saige-
Avatar of XTO

ASKER

The statement from it_saige, ". . .  if you are constraining to one type, then there really is no need to use the generic implementation.  Using the explicit type definition better illustrates your intention," lets me know that I'm on the right track; and it adds the helpful comment that the programming intention is better shown with the type definition. Thanks.
Avatar of XTO

ASKER

Your implementation of the ParseHttpResponseMsgFactory method with generics is spot on. I had felt that implementation forming in my mind, but you beat me to it. Ha, good job. Thanks for your help.
One closing comment, I also noticed another pattern.  So ultimately we could have written your ParseHttpResponseMsgFactory as such:
interface IDeserializeToObject<T> where T : IHttpResponseResults
{
	T DeserializeMessageToObject<T>(string postResult);
}

public static T ParseHttpResponseMsgFactory<T, D>(HttpResponseMessage respMessage) where T : IHttpResponseResults where D : IDeserializeToObject<T>, new()
{
	T respResult = default(T);
	D deserializer = Activator.CreateInstance<D>();
	if (respMessage.IsSuccessStatusCode)
	{
		string postResult = respMessage.Content.ReadAsStringAsync().Result;
		respResult = deserializer.DeserializeMessageToObject<T>(postResult);
	}
	respResult.StatusCode = respMessage.StatusCode.ToString();
	respResult.ReasonPhrase = respMessage.ReasonPhrase;
	return respResult;
}

Open in new window

Which now makes your calls look like such:
AgsServiceStatus serviceStatus = HttpHelpers.ParseHttpResponseMsgFactory<AgsServiceStatus, JsonHelper>(chkServiceRsp);

Open in new window

Or
AgsToken token = HttpHelpers.ParseHttpResponseMsgFactory<AgsToken, XmlHelper>(respMessage);

Open in new window

This assumes that both XmlHelper and JsonHelper implement the IDeserializeToObject<T> interface and have a public parameterless constructor.

-saige-
@XTO - Not a problem.  Glad I was able to help.

-saige-
My point had nothing to do with simple types. My point was in regards to the burden of work (i.e. compiler vs. you). I challenge you to write a framework designed around interfaces that does not force me to hand-code an implementation for every variation I might encounter. If you can do that, then you've defeated my argument.