Приведение к абстрактному классу или интерфейсу при использовании дженериков - PullRequest
2 голосов
/ 21 января 2009

У меня есть этот метод Verify_X, который вызывается во время привязки данных для выбранного в списке значения. Проблема заключается в строго типизированном источнике данных. Я хочу использовать абстрактный класс BaseDataSource или интерфейс для вызова поддерживаемых методов: Параметры [] и Select (), вместо использования наиболее конкретной реализации, как показано ниже.

Это так, что один метод можно использовать для всех различных типов источников данных, которые у меня есть, вместо того, чтобы иметь метод для каждого. Все они наследуют одинаково.

Вот цепочка наследования / реализации

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()

BaseDataSource содержит методы и свойства, которые мне нужны. DseDataSource реализован следующим образом:

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

Я знаю, что можно отредактировать класс DseDataSource, добавить интерфейс для доступа к параметрам [] и Select (), а затем запрограммировать его, что позволяет то, что я хочу, но это требует редактирования библиотек NetTiers, и мне любопытно посмотрим, можно ли это сделать, потому что это казалось таким трудным.

    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;
    }

Конечным результатом будет код, такой как:

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;
}

Ответы [ 3 ]

2 голосов
/ 21 января 2009

Если вы не можете изменить определение класса или использовать какие-либо методы расширения, вы можете использовать Reflection. Вот пример, который я разработал, используя предположения о вашем коде:

    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;
    }
1 голос
/ 21 января 2009

Спасибо, Джон, ты действительно поставил меня на правильный путь. Я получил следующий код:

    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;
    }
0 голосов
/ 21 января 2009

Поскольку код не может использоваться "как есть", очень трудно обсудить реальную проблему ... Вы можете упростить пример до того, что не зависит от внешних библиотек / классов?

Могу ли я подтвердить: DseDataSource генерируется из NetTiers? В каком случае NetTiers генерирует «частичные» классы? Если это так, вы можете добавить реализацию интерфейса в файл второго класса:

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

Это добавляет функциональность к классу DseDataSource без необходимости редактирования сгенерированного кода.

...