0
  • summary

    Ignore the case that an object cannot represented as an array, is it possible to define an extension(static) method like:

    public static ? ToArray<TSource>(this TSource source); 
    

    and returns the array of an object if it consists of whatever a sequence of elements? And if yes, what would the ? be?

  • explanation

    I've thought about the following declarations:

    public static TElement[] ToArray<TElement>(this IEnumerable<TElement> source); 
    public static ? ToArray<TSource>(this IEnumerable source); 
    

    But I cannot assume an unknown class must have implemented IEnumerable<T> or IEnumerable. I cannot even define the ? in the case it is just IEnumerable which is out of generic definition.

    And I've also thought about the Array class:

    public static Array ToArray<TSource>(this TSource source); 
    

    But that means the element type was unknown at compile time.

    So I'm wondering is it possible to know the element type at compile time without a class implementing IEnumerable<T>?

Ken Kin
  • 4,503
  • 3
  • 38
  • 76
  • Take a look at Generic Constraints, as described on MSDN. This may point you in the right direction. http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx – Maurice Reeves Dec 30 '12 at 06:07
  • 1
    If the class doesn't implement IEnumerable or IEnumerable, how would anyone have any way of finding its "elements"? How would you describe a class as having "elements" if it didn't implement IEnumerable? Even if a class defines an `[int index]` indexer, there's no predefined way of determining what the allowed indexes are. – JLRishe Jan 14 '13 at 15:48
  • Because my English is poor. If I later find something may lead misunderstood, I roll back and try to correct. Is this the answer to your question? – Ken Kin Jan 20 '13 at 13:04

3 Answers3

1

Unfortunately, IEnumerator predates generics so it carries with it no type information; just a IEnumerator GetEnumerator() making String not so appealing to try and force into this generic implementation you're trying to accomplish.

It's been a long time since I've done C# but I imagine:

public static TElement ToArray<TSource>(this IEnumerable<TElement> source);

... should be fine as:

public static TElement[] ToArray<TElement>(this IEnumerable<TElement> source);

The important thing to keep in mind about extension methods is they are just syntax sugar. They don't actually stick around or become injected into the types they are decorating. They are replaced at compile time to static method invocations. Your mileage with extension methods will vary.

Ken Kin
  • 4,503
  • 3
  • 38
  • 76
cfeduke
  • 23,100
  • 10
  • 61
  • 65
  • 2
    In the case of `public static ? ToArray(this IEnumerable source);` you simply cannot get anymore type-specific than `object[]` because `IEnumerable` implies no restrictions on its `GetEnumerator` method other than the returned instance implement `IEnumerator`. This does not imply that the element type is not inferable at compile time, it just means at the time of `IEnumerable` there was no mechanism to carry additional type information forward to the call site. – cfeduke Dec 30 '12 at 06:41
  • 1
    Yes the consumer will have to cast it, there's no two ways about it, and no you [ahem, the compiler] cannot enforce a safe cast. Contrast this to Java, which has generic support but has type erasure - `?` as a generic type argument *is* a valid type descriptor but this is only because in Java generics are there to enforce type safety during compilation time. Runtime performance of casts isn't a problem, if that's what you're concerned about. Runtime type safety of unsafe casts, well yes, that is absolutely a problem you have to pay very close attention to. – cfeduke Dec 30 '12 at 07:02
1

What is your question specifically? If you are asking whether the type of elements in an IEnumerable is always known at compile time, then the answer is "no, it is not always known". The non-generic IEnumerable does not enforce any element type. This is why you can define a foreach loop on any IEnumerable:

IEnumerable items = GetItems();

foreach(SomeClass item in items)
{
   ...
}

but this will throw an InvalidCastException if one of the elements of items cannot be cast to a SomeClass.

Incidentally, if you define a method like this:

public static TElement[] MyToArray<TElement>(this IEnumerable<TElement> source); 

Then you can call it on a string in .NET 2.0+, because string implements IEnumerable<string> in .NET 2.0 and 3.0, and IEnumerable<char> in 3.5+. In fact, the .ToArray() extension that's built into .NET can already be used on string without you defining anything.

JLRishe
  • 99,490
  • 19
  • 131
  • 169
1

It's not known at compile time, and it cannot be known.

For example I could do:

IEnumerable myCollection;
string discriminator = Console.ReadLine();
if (discriminator == "string")
{
   myCollection = new List<string>{"One", "Two", "Three", "Four"};
}
else 
{
   myCollection =  new int[]{1, 2, 3, 4};
}

//what should be the type of the elements variable
var elements = myCollection.ToArray();

Basically, depending on user input, myCollection will be either a List<string> or an int[], two types, that have almost nothing in common, except being enumerable.

So, in order for your ToArray method to work, you can either introduce type safety and generics, using IEnumerable<T> instead of IEnumerable, or use a collection of objects, such as object[] as the return type of your method.

SWeko
  • 30,434
  • 10
  • 71
  • 106