The emphasis of my question is with C# Generics and the passing of the interface IXList -or- IYList to this 'GetAllValues()' method. The goal is common code for calling GetAllValues<IXList>()
-or- GetAllValues<IYList>()
.
09-21-13 Follow up:
I have learned that: where Z : IXList, IYList
means that Z is of type IXList
and ITList
-- given this understanding one might try where Z : class
- this is at best a lateral step of still not working because then Z.anything
... anything
is not found, the compiler is clueless about Z
...
Can the actual type of Z passed be tested and then conditional run-time
code pick correct casted list
to call .Head(), .Get(), and .Next() accordingly?
e.g., ((IXList)list).Head();
-or- ((IYList)list).Head();
[[ Yes it is possible, please see 2nd answer with code below dated 09-24-13.]]
09-29-13 Follow up: And finally, answer/solution #3 posted below moves the final solution to a more object oriented one. And thus, this 3rd solution renders moot my initial question on how to ask the type of generic and how to solve the compiler ambiguity error encountered initially. [[ Please see answer/solution #3, with code below dated 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);
}
Solution #3: by-far the best, no need to cast anything, no need to ask the type of the input list (repeatedly), much much cleaner. Please compare with Answer/Solution #2 above.
(#3) accomplishes exactly the goal I was seeking, common code for the logic that process either IXList or IYList. And as an extension method the user gets the 'GetAllItems' typed version desired...
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;
}
}