【问题标题】:Casting to abstract class or interface when generics are used使用泛型时转换为抽象类或接口
【发布时间】:2009-01-21 02:09:32
【问题描述】:

我有这个方法 Verify_X,它在数据绑定期间为列表框选定值调用。问题是强类型数据源。我想使用抽象类 BaseDataSource 或接口来调用支持的方法: Parameters[] 和 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 类,添加一个接口来访问 Parameters[] 和 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;
}

【问题讨论】:

    标签: c# reflection casting abstract-class generics


    【解决方案1】:

    如果您无法更改类定义或使用某种扩展方法,则可以使用反射。这是我使用有关您的代码的假设处理的示例:

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

    【讨论】:

      【解决方案2】:

      感谢约翰,你真的让我走上了正确的道路。 我最终得到了以下代码:

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

      【讨论】:

        【解决方案3】:

        由于代码不能“按原样”使用,因此很难讨论实际问题...您能否将示例简化为不依赖外部库/类的内容?

        我可以确认:DseDataSource 是从 NetTiers 生成的吗?在这种情况下,NetTiers 会生成“部分”类吗?如果是这样,您可以在第二个类文件中添加接口实现:

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

        这为DseDataSource 类添加了功能,而无需您编辑生成的代码。

        【讨论】:

        • 不,它不使用部分类,但是是的,这将是创建接口的好方法。我可以编辑 NetTiers 模板以使其成为部分模板或在那里制作界面。但我在看是否可以用那里的东西来做演员。
        • 很难回答铸造问题,因为它根本不清楚(从示例中)您要投射什么、投射到什么、在哪里。你能把它归结为实际问题吗?
        • 好的,谢谢,请看我刚刚编辑的帖子底部。
        猜你喜欢
        • 2014-02-19
        • 1970-01-01
        • 2010-11-08
        • 1970-01-01
        • 2019-09-16
        • 2020-05-14
        • 2014-11-05
        相关资源
        最近更新 更多