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:
Here is an example that uses an interface:
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
Here is an example that uses a generic method:
internal T DoSomething<T>(T value) where T : IDoIt
{
return value;
}
Here is an example that uses an interface:
internal IDoIt DoSomething(IDoIt value)
{
return value;
}
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
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.
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:
-saige-
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!!!"; } }
}
}
-saige-
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( );
}
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.
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:
This, then, becomes the generic pattern to use:
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;
}
}
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;
}
}
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;
}
}
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));
}
}
}
So using the above pattern we can now write code like this:
tbName.HandleInvokeRequired(x => x.Text = "Awsome...")
-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.
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.
As with anything, they have their uses, and you should pick the use and paradigm that fits the problem at hand.
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:
All,
So, of the two examples in my question, is there any advantage of one over the other. I appreciate your help.
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; }
}
}
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
As I understand it, the System.Windows.Forms.Contr ol 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,
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?
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;
}
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?
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:
The IDeserializeToObject looks like this:
y like this,
Then I could call my HttpHelpers.ParseHttpRespo nseMsgFact ory like this:
> method would not know what type of IHttpResponseResults to create.
I had these two lines of code which were getting called repeatedly:
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
return jsSerializer.Deserialize<T>(postResult);
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);
}
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;
}
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);
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;
}
Then I added the IDeserializeToObject as a parameter to my ParseHttpResponseMsgFactorpublic 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;
}
And I call it like this:AgsToken = HttpHelpers.ParseHttpResponseMsgFactory(
new AGSToken(),
respMessage,
new JsonHelper()) as AGSToken;
Or I could call it like this:AgsServiceStatus serviceStat = HttpHelpers.ParseHttpResponseMsgFactory(
new AgsServiceStatus(),
chkServiceRsp,
new JsonHelper()) as AgsServiceStatus;
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.ParseHttpRespo
AgsToken = HttpHelpers.ParseHttpResponseMsgFactory(
new AGSToken(),
respMessage,
new XmlHelper()) as AGSToken;
Or I could call it like this:AgsServiceStatus serviceStat = HttpHelpers.ParseHttpResponseMsgFactory(
new AgsServiceStatus(),
chkServiceRsp,
new XmlHelper()) as AgsServiceStatus;
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);
}
And the jsSerializer.Deserialize<T
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;
}
And now your call becomes:
AgsServiceStatus serviceStatus = HttpHelpers.ParseHttpResponseMsgFactory<AgsServiceStatus>(chkServiceRsp, new JsonHelper());
Or:
AgsToken token = HttpHelpers.ParseHttpResponseMsgFactory<AgsToken>(respMessage, new XmlHelper());
-saige-
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.
ASKER
Your implementation of the ParseHttpResponseMsgFactor y 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 ParseHttpResponseMsgFactor y as such:
-saige-
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;
}
Which now makes your calls look like such:
AgsServiceStatus serviceStatus = HttpHelpers.ParseHttpResponseMsgFactory<AgsServiceStatus, JsonHelper>(chkServiceRsp);
Or
AgsToken token = HttpHelpers.ParseHttpResponseMsgFactory<AgsToken, XmlHelper>(respMessage);
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-
-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.
Open in new window
Which produces the following output -But 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. -
Open in new window
Which now produces the following output -Again 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. -
Open in new window
No need for generics, or reflection.-saige-