Finding controls that use a certain interface in ASP.NET - c#

Having a heckuva time with this one, though I feel I'm missing something obvious. I have a control that inherits from System.Web.UI.WebControls.Button, and then implements an interface that I have set up. So think...
public class Button : System.Web.UI.WebControls.Button, IMyButtonInterface { ... }
In the codebehind of a page, I'd like to find all instances of this button from the ASPX. Because I don't really know what the type is going to be, just the interface it implements, that's all I have to go on when looping through the control tree. Thing is, I've never had to determine if an object uses an interface versus just testing its type. How can I loop through the control tree and yank anything that implements IMyButtonInterface in a clean way (Linq would be fine)?
Again, know it's something obvious, but just now started using interfaces heavily and I can't seem to focus my Google results enough to figure it out :)
Edit: GetType() returns the actual class, but doesn't return the interface, so I can't test on that (e.g., it'd return "MyNamespace.Button" instead of "IMyButtonInterface"). In trying to use "as" or "is" in a recursive function, the type parameter doesn't even get recognized within the function! It's rather bizarre. So
if(ctrl.GetType() == typeToFind) //ok
if(ctrl is typeToFind) //typeToFind isn't recognized! eh?
Definitely scratching my head over this one.

Longhorn213 almost has the right answer, but as as Sean Chambers and bdukes say, you should use
ctrl is IInterfaceToFind
instead of
ctrl.GetType() == aTypeVariable
The reason why is that if you use .GetType() you will get the true type of an object, not necessarily what it can also be cast to in its inheritance/Interface implementation chain. Also, .GetType() will never return an abstract type/interface since you can't new up an abstract type or interface. GetType() returns concrete types only.
The reason this doesn't work
if(ctrl is typeToFind)
Is because the type of the variable typeToFind is actually System.RuntimeType, not the type you've set its value to. Example, if you set a string's value to "foo", its type is still string not "foo". I hope that makes sense. It's very easy to get confused when working with types. I'm chronically confused when working with them.
The most import thing to note about longhorn213's answer is that you have to use recursion or you may miss some of the controls on the page.
Although we have a working solution here, I too would love to see if there is a more succinct way to do this with LINQ.

You can just search on the Interface. This also uses recursion if the control has child controls, i.e. the button is in a panel.
private List<Control> FindControlsByType(ControlCollection controls, Type typeToFind)
{
List<Control> foundList = new List<Control>();
foreach (Control ctrl in this.Page.Controls)
{
if (ctrl.GetType() == typeToFind)
{
// Do whatever with interface
foundList.Add(ctrl);
}
// Check if the Control has Child Controls and use Recursion
// to keep checking them
if (ctrl.HasControls())
{
// Call Function to
List<Control> childList = FindControlsByType(ctrl.Controls, typeToFind);
foundList.AddRange(childList);
}
}
return foundList;
}
// Pass it this way
FindControlsByType(Page.Controls, typeof(IYourInterface));

I'd make the following changes to Longhorn213's example to clean this up a bit:
private List<T> FindControlsByType<T>(ControlCollection controls )
{
List<T> foundList = new List<T>();
foreach (Control ctrl in this.Page.Controls)
{
if (ctrl as T != null )
{
// Do whatever with interface
foundList.Add(ctrl as T);
}
// Check if the Control has Child Controls and use Recursion
// to keep checking them
if (ctrl.HasControls())
{
// Call Function to
List<T> childList = FindControlsByType<T>( ctrl.Controls );
foundList.AddRange( childList );
}
}
return foundList;
}
// Pass it this way
FindControlsByType<IYourInterface>( Page.Controls );
This way you get back a list of objects of the desired type that don't require another cast to use. I also made the required change to the "as" operator that the others pointed out.

Interfaces are close enough to types that it should feel about the same. I'd use the as operator.
foreach (Control c in this.Page.Controls) {
IMyButtonInterface myButton = c as IMyButtonInterface;
if (myButton != null) {
// do something
}
}
You can also test using the is operator, depending on your need.
if (c is IMyButtonInterface) {
...
}

Would the "is" operator work?
if (myControl is ISomeInterface)
{
// do something
}

If you're going to do some work on it if it is of that type, then TryCast is what I'd use.
Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
'do work
End if

you can always just use the as cast:
c as IMyButtonInterface;
if (c != null)
{
// c is an IMyButtonInterface
}

Related

Creating an object via lambda factory vs direct "new Type()" syntax

For example, consider a utility class SerializableList:
public class SerializableList : List<ISerializable>
{
public T Add<T>(T item) where T : ISerializable
{
base.Add(item);
return item;
}
public T Add<T>(Func<T> factory) where T : ISerializable
{
var item = factory();
base.Add(item);
return item;
}
}
Usually I'd use it like this:
var serializableList = new SerializableList();
var item1 = serializableList.Add(new Class1());
var item2 = serializableList.Add(new Class2());
I could also have used it via factoring, like this:
var serializableList = new SerializableList();
var item1 = serializableList.Add(() => new Class1());
var item2 = serializableList.Add(() => new Class2());
The second approach appears to be a preferred usage pattern, as I've been lately noticing on SO. Is it really so (and why, if yes) or is it just a matter of taste?
Given your example, the factory method is silly. Unless the callee requires the ability to control the point of instantiation, instantiate multiple instances, or lazy evaluation, it's just useless overhead.
The compiler will not be able to optimize out delegate creation.
To reference the examples of using the factory syntax that you gave in comments on the question. Both examples are trying (albeit poorly) to provide guaranteed cleanup of the instances.
If you consider a using statement:
using (var x = new Something()) { }
The naive implementation would be:
var x = new Something();
try
{
}
finally
{
if ((x != null) && (x is IDisposable))
((IDisposable)x).Dispose();
}
The problem with this code is that it is possible for an exception to occur after the assignment of x, but before the try block is entered. If this happens, x will not be properly disposed, because the finally block will not execute. To deal with this, the code for a using statement will actually be something more like:
Something x = null;
try
{
x = new Something();
}
finally
{
if ((x != null) && (x is IDisposable))
((IDisposable)x).Dispose();
}
Both of the examples that you reference using factory parameters are attempting to deal with this same issue. Passing a factory allows for the instance to be instantiated within the guarded block. Passing the instance directly allows for the possibility of something to go wrong along the way and not have Dispose() called.
In those cases, passing the factory parameter makes sense.
Caching
In the example you have provided it does not make sense as others have pointed out. Instead I will give you another example,
public class MyClass{
public MyClass(string file){
// load a huge file
// do lots of computing...
// then store results...
}
}
private ConcurrentDictionary<string,MyClass> Cache = new ....
public MyClass GetCachedItem(string key){
return Cache.GetOrAdd(key, k => new MyClass(key));
}
In above example, let's say we are loading a big file and we are calculating something and we are interested in end result of that calculation. To speedup my access, when I try to load files through Cache, Cache will return me cached entry if it has it, only when cache does not find the item, it will call the Factory method, and create new instance of MyClass.
So you are reading files many times, but you are only creating instance of class that holds data just once. This pattern is only useful for caching purpose.
But if you are not caching, and every iteration requires to call new operator, then it makes no sense to use factory pattern at all.
Alternate Error Object or Error Logging
For some reason, if creation fails, List can create an error object, for example,
T defaultObject = ....
public T Add<T>(Func<T> factory) where T : ISerializable
{
T item;
try{
item = factory();
}catch(ex){
Log(ex);
item = defaultObject;
}
base.Add(item);
return item;
}
In this example, you can monitor factory if it generates an exception while creating new object, and when that happens, you Log the error, and return something else and keep some default value in list. I don't know what will be practical use of this, but Error Logging sounds better candidate here.
No, there's no general preference of passing the factory instead of the value. However, in very particular situations, you will prefer to pass the factory method instead of the value.
Think about it:
What's the difference between passing the parameter as a value, or
passing it as a factory method (e.g. using Func<T>)?
Answer is simple: order of execution.
In the first case, you need to pass the value, so you must obtain it before calling the target method.
In the second case, you can postpone the value creation/calculation/obtaining till it's needed by the target method.
Why would you want to postpone the value creation/calculation/obtaining? obvious things come to mind:
Processor-intensive or memory-intensive creation of the value, that you want to happen only in case the value is really needed (on-demand). This is Lazy loading then.
If the value creation depends on parameters that are accessible by the target method but not from outside of it. So, you would pass Func<T, T> instead of Func<T>.
The question compares methods with different purposes. The second one should be named CreateAndAdd<T>(Func<T> factory).
So depending what functionality is required, should be used one or another method.

How to call a C# method only if it exists?

Is this possible without reflection otherwise with reflection ? This is something very often used in PHP like in Wordpress.
Something in pseudo code:
if (exists(object.method)) {object.method}
or
try {object.method} finally {...}
Well, you could declare it in an interface, and then use:
IFoo foo = bar as IFoo;
if (foo != null)
{
foo.MethodInInterface();
}
That assumes you can make the object's actual type implement the interface though.
Otherwise you'd need to use reflection AFAIK.
(EDIT: The dynamic typing mentioned elsewhere would work on .NET 4 too, of course... but catching an exception for this is pretty nasty IMO.)
You could use dynamics and catch the Runtime exception:
dynamic d = 5;
try
{
Console.WriteLine(d.FakeMethod(4));
}
catch(RuntimeBinderException)
{
Console.WriteLine("Method doesn't exist");
}
Although it sounds more like a design problem.
Disclaimer
This code is not for use, just an example that it can be done.
Use .GetType().GetMethod() to check if it exists, and then .Invoke() it.
var fooBar = new FooBarClass();
var method = fooBar.GetType().GetMethod("ExistingOrNonExistingMethod");
if (method != null)
{
method.Invoke(fooBar, new object[0]);
}
With the dynamic type in C# 4.0, you could do something like this:
dynamic obj = GetDynamicObject();
if (obj != null && obj.GetType().GetMethod("DoSomething") != null)
{
obj.DoSomething();
}
But the only way to tell if a type has a method in the first place is to use reflection; so the above approach doesn't really buy you anything (you might as well take the MethodInfo you get from calling GetMethod and just Invoke it).
Edit: If you're open to trying to call the method even when it's not there, then Yuriy's answer is probably what you're looking for. My original answer was a literal response to the way you worded your question: "How to call a C# method only if it exists."
I came across this looking for the same answer but did not like any of the solutions.
here is mine:
//Invoke the refresh method if the datasource contains it
if (this.DataSource.GetType().GetMethod("Refresh") != null)
this.DataSource.GetType().GetMethod("Refresh").Invoke(this.DataSource, new object[] { });
You should revise existance first. MethodInfo[] myArrayMethodInfo = myType.GetMethods();

C# Generics - Accepting different types

I am trying to write a generic method so I can avoid code duplication. The generic method has to be able to accept one of three different grid view types however I cannot get the following cast to work at the start of the generic method;
var grid;
if (typeof(T) == typeof(GridView))
{
grid = (GridView)gridView;
}
else if (typeof(T) != typeof(BandedGridView))
{
grid = (BandedGridView)gridView;
}
else if (typeof(T) != typeof(AdvBandedGridView))
{
grid = (AdvBandedGridView)gridView;
}
else return;
How can I cast "grid" to either of the three types so I can then do something with them. I am still trying to grasp the idea and concept behind Generics.
If BrandedGridView and AdvBrandedGridView both inherit from GridView you can add a constraint to your generic
...<T> where T : GridView
If not you can use Convert.ChangeType:
Try Convert.ChangeType:
if (typeof(T) == typeof(GridView))
{
var grid = (GridView)Convert.ChangeType(gridView, typeof(GridView));
}
elseif (typeof(T) == typeof(BrandedGridView))
{
var grid = (BrandedGridView)Convert.ChangeType(gridView, typeof(BrandedGridView));
}
You want to constrain type T to something (likely GridView as 2 other types are likely derive from it) so C# knows what method the T has, otherwise it is just of type Object.
public class MyClass<T> where T : GridView
Please read article about generic on MSDN to get more details - http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx#csharp_generics_topic4
Note: As mentioned above C# is not JavaScript and "var" does not mean "a type" it is just shorter way to declare object of type of the right side. I.e. in var my = new List() var is synonim for List.
"methods are identical except for the parameter type"
I think you should just make a new method that has the different parameter type of the view as the actual parameters. They're the ones that are different after all.

Using "as" and expecting a null return

For example. Lets say we have a stackpanel on a form. Its full of both Grids and Labels. I want to loop through all the Grids and do some operation on them but leave the Lables intact. At the moment I am doing it this way.
foreach(UIElement element in m_stacker.Children)
{
Grid block = element as Grid;
if(block != null)
{
//apply changes here
}
}
So i'm using the fact that "as" returns null if it cannot cast into the required type. Is this an ok thing to do or is there a better solution to this problem?
What about OfType()?
foreach( var grid in m_stacker.Children.OfType<Grid>() ) { ... }
This will loop only over the children of type Grid, so no need to cast or check the type at all.
Yes, it's the right way to do it (considering "applying changes" will need to use the cast result).
However, if you are not going to use the cast return value, you can simply use is.
Using is and then casting again with the cast operator (parenthesis) is frowned upon.
It will work fine. What you can do is however just use "is".
foreach(UIElement element in m_stacker.Children)
{
if(element is Grid)
{
//apply changes here
}
}
If you are going to use block as a Grid then this is exactly the right way to code it.
Checking using is (to my mind) produces less readable code as illustrated in the following two bad examples:
if (element is Grid)
{
Grid block = element as Grid;
// Do stuff
}
if (element is Grid)
{
Grid block = (Grid)element;
// Do stuff
}
Don't do either of these.
You're saying if element is a grid then cast it.

How do I write a method that can output data from any class using generics?

I'm trying to write a custom method to populate a ListView control using Generics:
private void BindDataToListView(List<T> containerItems)
{
this.View = View.Details;
this.GridLines = true;
this.FullRowSelect = true;
if (this.Items.Count > 0)
this.Items.Clear();
this.BeginUpdate();
int i = 0;
foreach (T item in containerItems)
{
// do something
}
this.EndUpdate();
}
The parameter containerItems can have many items since I'm using generics. But I get stuck in the foreach loop. How do I access the values in containerItems?
Do I have to use reflection on each instance of T in the foreach loop? I think I do to retrieve the property name. But once I have the property name of the type T, how do I retrieve the value?
The most common way of doing this (with winforms) is via TypeDescriptor; this allow you to use things DataTable the same as classes; the "full" pattern is quite complex (and involves checking for IListSource, ITypedList, etc; however, the short version is; to get the available properties:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
To get a named property:
PropertDescriptor prop = props[propName];
To get a value for an instance (sourceObject):
object val = prop.GetValue(sourceObject);
To render a value as a string (using the designated converter):
string s = prop.Converter.ConvertToString(val);
You could limit T to an interface, and use that interface in the iteration.
What does T represent ?
Like it is now, it is a generic type and it can be ... anything.
So, what I would do, is create an interface IListViewBindable or something like that. That interface could then have a method 'CreateListViewItem' for instance.
Then, I would change the method, so that a constraint is applied to your type-parameter T, saying that T should implement IListViewBindable, like this:
public void BindDataToListView<T>( List<T> containerItems ) where T : IListViewBindable
{}
In your BindDataToListView method, you could then do this:
foreach( T item in containerItems )
{
this.Items.Add (item.CreateListViewItem());
}
If the items in the list are of totally unconstrained type, then you can treat them as simply of type object. You call GetType() to get the type of the object. On that you can call GetProperties() to get an array of PropertyInfo objects. And on those you can call GetValue() to retrieve the value of the property.
If you already know the name of a property, just call GetProperty() to retrieve it:
string valueAsString = item.GetType().GetProperty("Something")
.GetValue(item, null).ToString();
I don't completely understand what you're asking, but I think that this will point you in the right direction. Please ask for clarification if it looks like it can help and it's unclear.
You can access a given property of an object using reflection via
object o;
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant");
and you can get the value via
object value = info.GetValue(o, null);
Now, if you're going to be accessing a property of the same name on objects of various types, you should consider adding an interface
public interface IHasThePropertyIWant {
object NameOfPropertyIWant { get; }
}
Then you can enforce this via
void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant
and use it in the look like so
foreach (T item in containerItems) {
object o = item.NameOfPropertyIWant;
// do something with o
}
ObjectListView uses reflection to do exactly what you are trying to do: populate a ListView using reflection. You could save yourself a lot of trouble by using it. It has already solved all the tricky problems you are going to encounter on this path.
If you really, really want to do it yourself, Marc's answer is (of course) completely correct.

Categories

Resources