1

我的问题的重点是C# 泛型以及将接口IXList -or- IYList 传递给这个“ GetAllValues ()”方法。目标是调用GetAllValues<IXList>()-or-的通用代码GetAllValues<IYList>()

2013 年 9 月 21 日跟进:我了解到:where Z : IXList, IYList意味着 Z 是类型IXList,并且ITList- 鉴于这种理解,人们可能会尝试where Z : class- 这充其量是仍然无法正常工作的横向步骤,因为那时Z.anything......anything没有找到,编译器对Z...一无所知

是否可以测试通过的 Z 的实际类型,然后有条件的运行时代码选择正确的类型list来调用 .Head()、.Get() 和 .Next()?例如, ((IXList)list).Head(); - 或 - ((IYList)list).Head(); [[ 是的,有可能,请参阅 2nd answer with code below 日期为 09-24-13。]]

13 年 9 月 29 日跟进:最后,下面发布的答案/解决方案#3将最终解决方案移至更面向对象的解决方案。因此,这第 3 个解决方案提出了我最初的问题,即如何询问泛型类型以及如何解决最初遇到的编译器歧义错误。[[请参阅答案/解决方案#3,代码如下,日期为 09-29-13。]]

    internal static IEnumerable<int> GetAllValues<Z>(Z list)
        where Z : IXList, IYList
    {
        try
        {
            list.Head();        // Error 344 - The call is ambiguous between the following
                                // methods or properties: 'IXList.Head()' and 'IYList.Head()'   
        }
        catch (Exception)
        {
            yield break;
        }

        do
        {
            IntPtr lineItemPointer;
            int x = list.Get();     // Error 345 - The call is ambiguous between the following
                                    // methods or properties: 'IXList.Get()' and 'IYList.Get()' 

            yield return x;

            try
            {
                list.Next();        // Error 346 -The call is ambiguous between the following
                                    // methods or properties: 'IXList.Next()' and 'IYList.Next()'   
            }
            catch (Exception)
            {
                yield break;
            }
        } while (true);
    } 
4

3 回答 3

2

由于您的代码现在是您的模板,因此您的模板要求 Z 是类 AND IXList 和 IYList ,因此您将无法使用此代码实现目标。为此,您需要一个用于 IXList 和 IYList 的通用接口,如下面的 IMyList 所示。如果您介绍,您只需将 where 语句更改为:

where Z : class, IMyList 

即使你真的需要类约束也要考虑。


至于歧义:

如果您可以修改接口 IXList、IYList 那么您可以排除那些公共部分以分离一个并从新的继承:

interface IMyList
{
    void Head();
    //....
}

inteface  IXList :IMyList { //....
inteface  IYList :IMyList { //....

这将解决歧义


如果出于某种原因您无法做到这一点,那么您唯一的选择是在每次通话时都在您的一个界面上进行投射

((IXList)list).Head();

这将解决歧义,但首先不是您想要的。如果你不能引入新的接口,那么拥有这个通用代码的唯一选择就是为每个列表类型实现这个扩展方法。

于 2013-09-20T05:44:28.463 回答
0

以下完全实现了我正在寻求的目标,即处理 IXList 或 IYList 的逻辑的通用代码。是的!

作为一种扩展方法,用户可以获得所需的“GetAllItems”类型的版本......

var landRecs = _land.MainXList().GetAllItems();

var landAltRecs = _land.AlternateYList().GetAllItems();

    internal static IEnumerable<Iint> GetAllItems(this IXList list)
    {
        return GetAllItemsGeneric<Iint, IXList>(list);
    }

    internal static IEnumerable<string> GetAllItems(this IYList list)
    {
        return GetAllItemsGeneric<string, IYList>(list);
    }                                                                                                                                   

    private static IEnumerable<Zout> GetAllItemsGeneric<Zout, T>(T list)
        where Zout : class      // (string -or- int)  -or-  (IReadOnlyTxnMisc or ITxnMisc) etc.
        where T : class         // IYList  -or- IXList  
    {
        try
        {
            DoHeadforList<T>(list);
        }
        catch (Exception)
        {
            yield break;
        }

        Guid guid = Marshal.GenerateGuidForType(typeof(Zout));

        do
        {
            Zout rec = null;
            try
            {
                IntPtr itemPointer;
                itemPointer = DoGetItemforList<T>(list, ref guid);
                rec = Marshal.GetObjectForIUnknown(itemPointer) as Zout;
            }
            catch (Exception)
            {
                yield break;
            }

            if (rec != null)
            {
                yield return rec;
            }
            else
            {
                yield break;
            }

            try
            {
                DoNextforList<T>(list);
            }
            catch (Exception)
            {
                yield break;
            }
        } while (true);
    }

    private enum IListType
    {
        X,
        Y,
        Unknown
    }

    private static IListType GetListTypeAsEnum<T>() where T : class
    {
        IListType rtType = IListType.Unknown;      
        Type inListType = typeof(T);

        if (inListType == typeof(IXList))
        {
            rtType = IListType.X;
        }
        else if (inListType == typeof(IYList))
        {
            rtType = IListType.Y;
        }
        return rtType;
    }

    private static IntPtr DoGetItemforList<T>(T list, ref Guid guid) where T : class
    {
        IntPtr itemPointer;
        if (list == null)
        {
            throw new ArgumentNullException("end of list");
        }
        switch (GetListTypeAsEnum<T>())
        {
            case IListType.X:
                ((IXList)list).GetItem(ref guid, out itemPointer);
                break;
            case IListType.Y:
                ((IYList)list).GetItem(ref guid, out itemPointer);
                break;
            default:
                throw new ArgumentException("unknown passed type");
        }
        return itemPointer;
    }

    private static void DoHeadforList<T>(T list) where T : class
    {
        if (list == null)
        {
            throw new ArgumentNullException("end of list");
        }
        switch (GetListTypeAsEnum<T>())
        {
            case IListType.X:
                ((IXList)list).Head();
                break;
            case IListType.Y:
                ((IYList)list).Head();
                break;
            default:
                throw new ArgumentException("unknown passed type");
        }
    }

    private static void DoNextforList<T>(T list) where T : class
    {
        if (list == null)
        {
            throw new ArgumentNullException("end of list");
        }
        switch (GetListTypeAsEnum<T>())
        {
            case IListType.X:
                ((IXList)list).Next();
                break;
            case IListType.Y:
                ((IYList)list).Next();
                break;
            default:
                throw new ArgumentException("unknown passed type");
        }
    }
于 2013-09-24T16:39:26.753 回答
0

解决方案#3:到目前为止最好的,不需要强制转换任何东西,不需要(重复)询问输入列表的类型,更干净。请与上面的答案/解决方案#2 进行比较。

(#3)完全实现了我所寻求的目标,即处理 IXList 或 IYList 的逻辑的通用代码。作为一种扩展方法,用户可以获得所需的“GetAllItems”类型的版本......

    internal static IEnumerable<IXOutList> GetAllLineItems(this IXList list)
    {
        TListEnumeratorBase genList = new IXListEnum(list);
        return GetAllLineItemsGeneric<IXOutList>(genList);
    }


    internal static IEnumerable<IYOutList> GetAllLineItems(this IYList list)
    {
        TListEnumeratorBase genList = new IYListEnum(list);
        return GetAllLineItemsGeneric<IYOutList>(genList);
    }                                                                                                                                   


    private static IEnumerable<Zout> GetAllLineItemsGeneric<Zout>(TListEnumeratorBase genList)
        where Zout : class     
    {
        try
        {
            genList.Head();
        }
        catch (Exception)
        {
            yield break;
        }

        Guid guid = Marshal.GenerateGuidForType(typeof(Zout));

        do
        {
            Zout rec = null;
            try
            {
                IntPtr lineItemPointer;
                lineItemPointer = genList.GetTxnItem(ref guid);
                rec = Marshal.GetObjectForIUnknown(lineItemPointer) as Zout;
            }
            catch (Exception)
            {
                yield break;
            }

            if (rec != null)
                yield return rec;
            else
                yield break;

            try
            {
                genList.Next();
            }
            catch (Exception)
            {
                yield break;
            }
        } while (true);
    }

    public abstract class TListEnumeratorBase
    {
        public abstract void Head();
        public abstract void Next();
        public abstract IntPtr GetTxnItem(ref Guid guid);
    }

    public class IXListEnum : TListEnumeratorBase
    {
        IXList _list;
        public IXListEnum(IXList list)
        {
            _list = list;
        }
        public override void Head()
        {
            _list.Head();
        }
        public override void Next()
        {
            _list.Next();
        }
        public override IntPtr GetTxnItem(ref Guid guid)
        {
            IntPtr lineItemPointer;
            _list.Get(ref guid, out lineItemPointer);
            return lineItemPointer;
        }
    }

    public class IYListEnum : TListEnumeratorBase
    {
        IYList _list;
        public IYListEnum(IYList list)
        {
            _list = list;
        }
        public override void Head()
        {
            _list.Head();
        }
        public override void Next()
        {
            _list.Next();
        }
        public override IntPtr GetTxnItem(ref Guid guid)
        {
            IntPtr lineItemPointer;
            _list.Get(ref guid, out lineItemPointer);
            return lineItemPointer;
        }
    }
于 2013-09-29T04:22:56.477 回答