views:

1068

answers:

3

I have this method Verify_X which is called during databind for a listbox selected value. The problem is the strongly typed datasource. I want to use the abstract class BaseDataSource or an interface to call the methods supported: Parameters[] and Select(), Instead of using the most specific implementation as seen below.

This is so one method can be used for all the different types of datasources I have instead of having a method for each. They all inherit the same way.

Here is the chain of inheritance / implementation

public class DseDataSource : ProviderDataSource<SCCS.BLL.Dse, DseKey>

public abstract class ProviderDataSource<Entity, EntityKey> : BaseDataSource<Entity, EntityKey>, ILinkedDataSource, IListDataSource
    where Entity : SCCS.BLL.IEntityId<EntityKey>, new()
    where EntityKey : SCCS.BLL.IEntityKey, new()

public abstract class BaseDataSource<Entity, EntityKey> : DataSourceControl, IListDataSource, IDataSourceEvents
    where Entity : new()
    where EntityKey : new()

The BaseDataSource has the methods and properties I need. DseDataSource is implemented the following way:

public class DseDataSource : ProviderDataSource<SCCS.BLL.Dse, DseKey>

I know it is possible to edit the class DseDataSource, add an interface to access Parameters[] and Select(), then program against that, which allows what I want, but this requires editing the NetTiers libraries and I am curious to see if this can be done since it seemed so difficult.

    public static string Verify_DSE(string valueToBind, DseDataSource dataSource)
    {
        if (ListContainsValue(dataSource.GetEntityList(), valueToBind)) return valueToBind;
        CustomParameter p = dataSource.Parameters["WhereClause"] as CustomParameter;
        if (p != null)
        {
            p.Value = "IsActive=true OR Id=" + valueToBind;
            dataSource.Select();
            return valueToBind;
        }
        return string.Empty;
    }

    private static bool ListContainsValue(IEnumerable list, string value)
    {
        if (value.Length == 0) return true;

        foreach (object o in list)
        {
            IEntity entity = o as IEntity;
            if (entity != null)
            {
                if (entity.Id.ToString() == value)
                    return true;
            }
        }
        return false;
    }

The end result would be code such as:

public static string Verify(string valueToBind, object dataSource)
{
//what is the correct way to convert from object
BaseDataSource baseInstance = dataSource as BaseDataSource;

if baseInstance != null)
{
 if (ListContainsValue(baseInstance.GetEntityList(), valueToBind)) return valueToBind;
 CustomParameter p = baseInstance.Parameters["WhereClause"] as CustomParameter;
 if (p != null)
 {
  p.Value = "IsActive=true OR Id=" + valueToBind;
  baseInstance.Select();
  return valueToBind;
 }
}

return string.Empty;
}
A: 

Because the code isn't usable "as is", it is very hard to discuss the actual problem... can you simplify the example to something that doesn't depend on external libraries / classes?

Can I confirm: is DseDataSource generated from NetTiers? In which case, does NetTiers generate "partial" classes? If so, you can add the interface-implementation in a second class file:

namespace YourNamespace {
    partial class DseDataSource : IYourInterface {
        // implement interface
    }
}

This adds functionality to the DseDataSource class without requiring you to edit the generated code.

Marc Gravell
No, it does not use a partial class but yes this would be a good way to create the interface. I could edit the NetTiers template to eiter make it partial or make the interface there. But I was seeing if the casting could be done with what is there.
CRice
It is hard to answer the casting question because it simply isn't clear (from the example) what you are trying to cast, to what, where. Can you boil it down to the actual problem at all?
Marc Gravell
Ok thanks, please see the bottom of the post I have just edited it.
CRice
+1  A: 

If you are unable to alter the class definition or to use some sort of extension methods, you can use Reflection. Here is a sample that I worked up using assumptions about your code:

    public static string Verify(string valueToBind, object dataSource)
    {
        ////what is the correct way to convert from object
        //BaseDataSource baseInstance = dataSource as BaseDataSource;
        Type type = dataSource.GetType();
        MethodInfo select = type.GetMethod("Select");
        PropertyInfo parameters = type.GetProperty("Parameters");
        PropertyInfo parameterGetter = null;
        object parametersInstance = null;
        if (parameters != null)
        {
            parametersInstance = parameters.GetValue(dataSource, null);
            type = parametersInstance.GetType();
            parameterGetter = type.GetProperty("Item");
        }

        //if baseInstance != null)
        if (select != null && parameters != null && parameterGetter != null)
        {
                if (ListContainsValue(baseInstance.GetEntityList(), valueToBind)) return valueToBind;
                CustomParameter p = parameterGetter.GetValue(parametersInstance, new object[] {"WhereClause" }) as CustomParameter;

                if (p != null)
                {
                        p.Value = "IsActive=true OR Id=" + valueToBind;
                        select.Invoke(dataSource, null);
                        return valueToBind;
                }
        }

        return string.Empty;
    }
John Fisher
+1  A: 

Thanks John you really put me on the right path there. I ended up with the following code:

    public string Verify(string valueToBind, object dataSource)
    {
        IListDataSource listDataSource = dataSource as IListDataSource;
        if (listDataSource != null)
        {
            if (ListContainsValue(listDataSource.GetEntityList(), valueToBind)) return valueToBind;
        }

        Type type = dataSource.GetType();
        MethodInfo select = type.GetMethod("Select", new Type[0]);
        PropertyInfo parameterCollectionInfo = type.GetProperty("Parameters");
        ParameterCollection pc = parameterCollectionInfo.GetValue(dataSource, null) as ParameterCollection;

        if (pc != null)
        {
            CustomParameter p = pc["WhereClause"] as CustomParameter;
            if (p != null)
            {
                p.Value = "IsActive=true OR Id=" + valueToBind;
                select.Invoke(dataSource, null);
                return valueToBind;
            }
        }

        return string.Empty;
    }
CRice