views:

74

answers:

1

Should be easy...

class Base{}    
class Foo:Base{}

public bool Bar(Type t){
  // return ???
  // NB: shouldn't know anything about Foo, just Base
}

Assert.True(Bar(typeof(IEnumerable<Foo>));
Assert.False(Bar(typeof(IEnumerable<Base>));
Assert.False(Bar(typeof(string));
Assert.False(Bar(typeof(Foo));

Just to answer question why 2nd one should be false (actually - it does not matter, cause Bar argument will never be IEnumerable<Base>).

I'm trying to write FluentNhibernate auto mapping convention which maps my class enumerations to integers. I successfully did that already, but things went down when I wanted to map IEnumerable<EnumerationChild> (in my case - User.Roles).

public class EnumerationConvention:IUserTypeConvention{
    private static readonly Type OpenType=typeof(EnumerationType<>);
    public void Apply(IPropertyInstance instance){
      //this is borked atm, must implement ienumerable case
      var closedType=OpenType.MakeGenericType(instance.Property.PropertyType);
      instance.CustomType(closedType);
    }
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria){
      criteria.Expect(
        x=>typeof(Enumeration).IsAssignableFrom(x.Property.PropertyType) ||  
           typeof(IEnumerable<Enumeration>)
             .IsAssignableFrom(x.Property.PropertyType));
    }
  }
+2  A: 

You can use Type.IsAssignableFrom(Type). However, your question isn't really clear - you're specifying one type, but you need two... which type is Bar meant to be checking t against?

Note that the answer will change between .NET 3.5 and .NET 4, due to generic covariance - in .NET 3.5, for example, a List<Foo> is not assignable to IEnumerable<Base>, but in .NET 4 it is.

EDIT: Here's a program which prints True, True, False, False. I'm not sure why you expected the second one to be false:

using System;
using System.Collections;
using System.Collections.Generic;

class Base{}    
class Foo:Base{}

class Test
{
    static bool Bar(Type t)
    {
        return typeof(IEnumerable<Base>).IsAssignableFrom(t);
    }

    static void Main()
    {
        Console.WriteLine(Bar(typeof(IEnumerable<Foo>)));
        Console.WriteLine(Bar(typeof(IEnumerable<Base>)));
        Console.WriteLine(Bar(typeof(string)));
        Console.WriteLine(Bar(typeof(Foo)));
    }
}
Jon Skeet
This will work if argument is `typeof(Foo)`. But as far as I know - it won't, if argument is `typeof(IEnumerable<Foo>)`.
Arnis L.
@Arnis: See my edit - are you using .NET 3.5 or .NET 4? Also note my edit where I ask which *two* types you're checking. You haven't specified which type should be checked against `IEnumerable<T>`.
Jon Skeet
Using c# 4 here. Tagged question.
Arnis L.
I need Bar to return true, if argument is IEnumerable of type that derives from Base.
Arnis L.
@Arnis: Then why is your second assertion false? You don't want to count `IEnumerable<Base>` itself as implementing `IEnumerable<Base>`?
Jon Skeet
That would be preferable, but might be acceptable if it's not.
Arnis L.
@Brian `Bar` should not see `Foo` directly. Otherwise - I would need to write down every class that derives from `Base`.
Arnis L.
@Arnis: I'd say it's a pretty confusing definition for it to not include itself, but anyway - see my edited answer. Note that this is dependent on the version of the *framework*, not the version of the *language*. If you compile this targeting .NET 3.5 but using the C# 4 compiler, you'll get False, True, False, False.
Jon Skeet