I have two generic classes implementing one interface.
public interface Interface1
{
//implementation
}
public interface Interface2<T>
{
//implementation
}
class Class1<T>: Interface2<T> where T : Interface1
{
//implementation
}
class Class2<T>: Interface2<T>
{
//implementation
}
I would like to write a method that returns object of one of these classes, depending on the type T.
Interface2<T> GetObject<T>()
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
//error
return new Class1<T>();
}
return new Class2<T>();
}
Implementation of Class1 must be limited to types implementing interface. Is there a way to convert type T to Interface1? Now I am obtaining error: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Class1'. There is no boxing conversion or type parameter conversion from 'T' to 'Test.Interface1'.
Full reflection would be:
return (Interface2<T>)Activator.CreateInstance(typeof(Class1<>).MakeGenericType(typeof(T)));
but it is slow (slow compared to doing a new Foo())... I don't find any other way. Note that you are already going partially in the reflection direction (the IsAssignableFrom)
Mmmh using the "caching" of static classes, we can cheat a little... We can produce at runtime the exact code needed for creating a new Class1<T> and cache it.
First version
static class Maker<T>
{
public static Func<Interface2<T>> Func { get; private set; }
public static Interface2<T> New()
{
if (Func == null)
{
Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class1<>).MakeGenericType(typeof(T)))).Compile();
}
return Func();
}
}
I use an expression tree that does the new Class1<T>. Then:
static Interface2<T> GetObject<T>()
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
return Maker<T>.New();
}
return new Class2<T>();
}
But still we can do something more. Given a type T, the result of the if in GetObject() can be precalculated and cached. We move the whole GetObject() inside the expression tree.
static class Maker2<T>
{
public static Func<Interface2<T>> Func { get; private set; }
public static Interface2<T> New()
{
if (Func == null)
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class1<>).MakeGenericType(typeof(T)))).Compile();
}
else
{
Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class2<>).MakeGenericType(typeof(T)))).Compile();
}
}
return Func();
}
}
and then
static Interface2<T> GetObject2<T>()
{
return Maker2<T>.New();
}
The solution that uses an expression tree is very slow the first time it is used for each type T, because it has to produce the expression tree and compile it, but then it becomes very fast. This compared to the version that uses the Activator.CreateInstance that is slow every time :-)
Related
In C#, I have a function that passes in T using generics and I want to run a check to see if T is an object that implements a interface and if so call one of the methods on that interface.
I don't want to have T constraints to only be of that Type. Is it possible to do this?
For example:
public class MyModel<T> : IModel<T> where T : MyObjectBase
{
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities));
}
return entities;
}
public IEnumerable<TResult> FilterMe<TResult>(IEnumerable<TResult> linked) where TResult : IFilterable
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id));
}
}
The error that I am getting is:
Error 21 The type 'TResult' cannot be used as type parameter 'TResult' in the generic type or method 'FilterMe(System.Collections.Generic.IEnumerable)'. There is no implicit reference conversion from 'TResult' to 'IFilterable'.
The missing piece is Cast<>():
if(typeof(IFilterable).IsAssignableFrom(typeof(T))) {
entities = FilterMe(entities.Cast<IFilterable>()).AsQueryable().Cast<T>();
}
Note the use of Cast<>() to convert the entities list to the correct subtype. This cast would fail unless T implements IFilterable, but since we already checked that, we know that it will.
if (typeof(IMyInterface).IsAssignableFrom(typeof(T))
This checks whether a variable of type IMyInterface can be assigned from an instance of type T.
If you have a generic-type parameter that may or may not implement IFoo, it's possible to as cast it to a storage location of type IFoo; if you do that, you may pass it to any method which expects an IFoo, as well as any method that expects a generic parameter constrained to IFoo, but you will lose all generic type information if you do that--the parameter will be passed as type IFoo. Among other things, this will mean that if your original object was a structure, it will be boxed.
If you wish to test whether a generic parameter type implements IFoo and call a method that takes a generic-constrained IFoo if it does, while keeping the original generic type (this could be useful if the type is a struct, and could be necessary if the type is being passed to a generic method which has both IFoo and IBar constraints and the things one might want to pass do not share any single common supertype), it will be necessary to use Reflection.
For example, suppose one wants to have a method Zap which takes a generic ref parameter, calls Dispose on it if it implements IDisposable, and clears it out. If the parameter is an IDisposable class type, a null test should be performed as an atomic operation with clearing out the parameter.
public static class MaybeDisposer
{
static class ClassDisposer<T> where T : class,IDisposable
{
public static void Zap(ref T it)
{
T old_it = System.Threading.Interlocked.Exchange(ref it, null);
if (old_it != null)
{
Console.WriteLine("Disposing class {0}", typeof(T));
old_it.Dispose();
}
else
Console.WriteLine("Class ref {0} already null", typeof(T));
}
}
static class StructDisposer<T> where T : struct,IDisposable
{
public static void Zap(ref T it)
{
Console.WriteLine("Disposing struct {0}", typeof(T));
it.Dispose();
it = default(T);
}
}
static class nonDisposer<T>
{
public static void Zap(ref T it)
{
Console.WriteLine("Type {0} is not disposable", typeof(T));
it = default(T);
}
}
class findDisposer<T>
{
public static ActByRef<T> Zap = InitZap;
public static void InitZap(ref T it)
{
Type[] types = {typeof(T)};
Type t;
if (!(typeof(IDisposable).IsAssignableFrom(typeof(T))))
t = typeof(MaybeDisposer.nonDisposer<>).MakeGenericType(types);
else if (typeof(T).IsValueType)
t = typeof(MaybeDisposer.StructDisposer<>).MakeGenericType(types);
else
t = typeof(MaybeDisposer.ClassDisposer<>).MakeGenericType(types);
Console.WriteLine("Assigning disposer {0}", t);
Zap = (ActByRef<T>)Delegate.CreateDelegate(typeof(ActByRef<T>), t, "Zap");
Zap(ref it);
}
}
public static void Zap<T>(ref T it)
{
findDisposer<T>.Zap(ref it);
}
}
The first time the code is invoked with any type T, it will determine what sort of generic static class can be produced for that parameter and use Reflection to create a delegate to call a static method of that generic class. Subsequent calls with the same type T will use the cached delegate. Even though Reflection can be a little slow, it will only need to be used once for any type T. All subsequent calls to MaybeDisposer.Zap<T>(ref T it) with the same type T will be dispatched directly through the delegate and will thus execute quickly.
Note that the calls to MakeGenericType will throw exceptions if they are given generic type parameters which do not meet the constraints of the given open generic classes (e.g. if T was a class or did not implement IDisposable, an attempt to make the generic type StructDisposer<T> would throw an exception); such tests occur at run-time and are not validated by the compiler, so you can use run-time checking to see if the types meet appropriate constraints. Note that the code does not test whether it implements IDisposable, but instead tests whether T does. This is very important. Otherwise, if MaybeDispose was called with a parameter of type Object which held a reference to a Stream, it would determine that it implemented IDisposable and thus try to create a ClassDisposer<Object>, crashing because Object does not implement IDisposable.
The simplest form I can come up with is something like:
public IEnumerable<T> GetRecords()
{
IQueryable<T> entities = new List<T>().AsQueryable();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
entities = FilterMe<IFilterable, T>(entities.OfType<IFilterable>()).AsQueryable();
}
return entities;
}
public IEnumerable<TResult> FilterMe<TSource, TResult>(IEnumerable<TSource> linked) where TSource : IFilterable
{
return linked.Where(r => true).OfType<TResult>();
}
The point here is the need to have types to pass into and get back out of the method. I had to change the types locally to get it working.
OfType will silently filter out items that are not really of a given type, so it assumes that it's a collection of the same type in any one call.
Because you are re-assigning from FilterMe, you still need the interface assignable check.
Is the OfType(...) method (link) what you're looking for?
public class MyModel<T> : IModel<T> where T : MyObjectBase
{
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities));
}
return entities;
}
public IEnumerable<TResult> FilterMe<TResult>(IEnumerable<TResult> linked) where TResult : IFilterable
{
var dict = GetDict();
return linked.OfType<TResult>().Where(r => dict.ContainsKey(r.Id));
}
}
In my answer, I assume that method FilterMe is used internally and should not be visible outside your model and could be marked private. If my assumption is wrong, you could create a private overload of FilterMe.
In my answer I just removed the generic <TResult>. I assume that this FilterMe always is about then entities of type T (since it is in the same Model class). This solves the problem about casting between T and TResult. TResult does not have to be marked as IFilterable since none of the members of IFilterable are used. And since the code already checks if T is IFilterable why check again (especially when FilterMe would be private)?
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities).AsQueryable();
}
return entities;
}
public IEnumerable<T> FilterMe(IEnumerable<T> linked)
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id));
}
If you would create a second FilterMe, replace the IEumerable<T> types with Queryable<T>, so you do not have to convert your entities with AsQueryable().
public IEnumerable<TResult> FilterMe<TResult>(IEnumerable<TResult> linked) where TResult : IFilterable
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id));
}
Try replacing FilterMe with this version:
public IEnumerable<T> FilterMe(IEnumerable<IFilterable> linked)
{
var dict = GetDict();
return linked.Where(r => dict.ContainsKey(r.Id)).Cast<T>();
}
Then, were you call, change your code to this:
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
var filterable = entities.Cast<IFilterable>();
entities = FilterMe(entities).AsQueryable();
}
You don't have to make the FilterMe method a generic method to achieve the same result.
public class MyModel<T> : IModel<T> where T : MyObjectBase {
public IQueryable<T> GetRecords()
{
var entities = Repository.Query<T>();
if (typeof(IFilterable).IsAssignableFrom(typeof(T)))
{
//Filterme is a method that takes in IEnumerable<IFilterable>
entities = FilterMe(entities.Cast<IFilterable>());
}
return entities;
}
public IEnumerable<T> FilterMe(IEnumerable<IFilterable> linked) {
var dict = GetDict();
return linked
.Where(r => dict.ContainsKey(r.Id))
.Cast<T>();
}
}
Eric Lippert has explained in his blog post at http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx why constraints are not considered for type inference, which makes sense given that methods cannot be overloaded by simply changing type constraints. However, I would like to find a way to instantiate an object using two generic types, one which can be inferred and another which could be inferred if constraints were considered, without having to specify any of the types.
Given the types:
public interface I<T>
{
Other<T> CreateOther();
}
public class C : I<string>
{
public Other<string> CreateOther()
{
return new Other<string>();
}
}
public class Other<T>
{
}
and the factory:
public static class Factory1
{
public static Tuple<T, Other<T1>> Create<T, T1>(T o) where T : I<T1>
{
return new Tuple<T, Other<T1>>(o, o.CreateOther());
}
}
the following desired code will not compile:
public void WontCompile()
{
C c = new C();
var v = Factory1.Create(c); // won't compile
}
The error message is "error CS0411: The type arguments for method 'yo.Factory1.Create(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.", which is in line with what Eric said in his blog post.
Thus, we can simply specify the generic type arguments explicitly, as the error message suggests:
public void SpecifyAllTypes()
{
C c = new C();
var v = Factory1.Create<C, string>(c); // type is Tuple<C, Other<string>>
}
If we don't wish to specify type arguments and we don't need to retain type C, we can use the following factory:
public static class Factory2
{
public static Tuple<I<T1>, Other<T1>> CreateUntyped<T1>(I<T1> o)
{
return new Tuple<I<T1>, Other<T1>>(o, o.CreateOther());
}
}
and now specify:
public void Untyped()
{
C c = new C();
var v = Factory2.CreateUntyped(c); // type is Tuple<I<string>, Other<string>>
}
However, I wish to retain type C in the returned object and not specify the types.
I came up with a solution to this problem, but it seems to be a kludge of a workaround, where the object of type C is used twice in a two-step factory call.
To do this, the following factories are used:
public static class Factory3
{
public static Factory<T1> CreateFactory<T1>(I<T1> o)
{
return new Factory<T1>();
}
}
public class Factory<T1>
{
public Tuple<T, Other<T1>> Create<T>(T o) where T : I<T1>
{
return new Tuple<T, Other<T1>>(o, o.CreateOther());
}
}
which can then be used as follows:
public void Inferred()
{
C c = new C();
var v = Factory3.CreateFactory(c).Create(c); // type is Tuple<C, Other<string>>
}
This just feels odd since c is used twice. The first time it is used it is actually discarded as it is just being used to infer the base type argument.
Is there a better solution to this problem where the object does not need to be used twice and the types do not need to be specified?
edit: I just realized that, although the object must be used twice, the second factory class is not needed. Rather, both parameters could just be used in the same factory method as follows:
public class Factory
{
public Tuple<T, Other<T1>> Create<T, T1>(T o, I<T1> o2) where T : I<T1>
{
return new Tuple<T, Other<T1>>(o, o.CreateOther());
}
}
This would be used as follows:
public void Inferred()
{
C c = new C();
var v = Factory.Create(c, c); // type is Tuple<C, Other<string>>
}
It's still not ideal, but better than having to create a second factory class, and at least XMLDoc comments could be used to indicate that both parameters should be the same object. Once again, the one parameter (o2 in this case) is only used to infer the constrained types for T.
I'm troubleshooting a problem that I have recreated in a solution here.
The issue is that I am using some custom types that can implicitly cast from string to themselves. One of the custom types inherits from the other.
public class CustomType
{
public string InnerString { get; protected set; }
public CustomType(string s)
{
InnerString = s;
}
#region Operator Overloads
public static implicit operator CustomType(string s)
{
if (s == null)
throw new ArgumentNullException();
return new CustomType(s);
}
public static implicit operator string(CustomType value)
{
if (value == null)
return null;
return value.InnerString;
}
#endregion
}
public class SubCustomType : CustomType
{
public SubCustomType(string s)
: base(s)
{
// Nada
}
#region Operator Overloads
public static implicit operator SubCustomType(string s)
{
if (s == null)
throw new ArgumentNullException();
return new SubCustomType(s);
}
public static implicit operator string(SubCustomType value)
{
if (value == null)
return null;
return value.InnerString;
}
#endregion
}
In another generic class, I rely upon the fact that the base custom type can implicitly cast from string to itself. (The cast occurs at the line (T)this.Rtf. .Rtf is a string.) (The generic class is in my case a subclass of RichTextBox, since that's what I was using when I ran into this problem.)
public class CustomRichTextBox<T> : Forms.RichTextBox
where T : CustomType
{
public object GetValue()
{
/// This line throws:
/// InvalidCastException
/// Unable to cast object of type 'TestCustomTypesCast.CustomType' to type 'TestCustomTypesCast.SubCustomType'.
return (T)this.Rtf;
}
}
public class SubCustomRichTextBox : CustomRichTextBox<SubCustomType>
{
}
When I use SubCustomRichTextBox (an instance of the generic class that has as type argument the SUB custom type), I get an InvalidCastException at the line where I cast to T in GetValue. What I think is going on is that in order for the compiler to be okay with the fact that I am using T to cast from string, it is looking at CustomType and seeing its cast overload. But even when I use a subclass of CustomType as the actual type argument, the compiler still looks to SubCustomType.CustomType(string s) to perform the cast, and not at the correct SubCustomType.SubCustomType(string s) method.
Can anyone point me in the direction of fixing this problem? I want to use the generic class because it would allow me to reuse the same code. If I can't use generics, then I'll need to duplicate code in several subclasses of CustomRichTextBox<T>. Thanks.
It's going to be hard because the operator overload is static, and you're essentially trying to get a virtual behaviour.
Try this:
public class CustomRichTextBox<T> : Forms.RichTextBox
where T : CustomType, new()
{
public object GetValue()
{
T t = new T();
t.InnerString = this.Rtf;
return t;
}
}
Note I've added new() to the type constraint. I also had to make InnerString public settable.
As an aside, you coule make the return type of GetValue() be T. That might be a nicer API.
I'm not sure how to phrase this question concisely without just giving the example so here goes:
public interface IThing<T>
{
void Do(T obj);
}
public class ThingOne : IThing<int>
{
public void Do(int obj)
{
}
}
public class ThingTwo : IThing<string>
{
public void Do(string obj)
{
}
}
public class ThingFactory
{
public IThing<T> Create<T>(string param)
{
if (param.Equals("one"))
return (IThing<T>)new ThingOne();
if (param.Equals("two"))
return (IThing<T>)new ThingTwo();
}
}
class Program
{
static void Main(string[] args)
{
var f = new ThingFactory();
// any way we can get the compiler to infer IThing<int> ?
var thing = f.Create("one");
}
}
The question appears to be here:
// any way we can get the compiler to infer IThing<int> ?
var thing = f.Create("one");
No. You would need to explicitly specify the type:
var thing = f.Create<int>("one");
You can't infer the return type without having a parameter used specifically in the method. The compiler uses the parameters passed to the method to infer the type T, and in this case, it's a single string parameter, with no parameters of type T. As such, there's no way to have this inferred for you.
No, you can't do this because the result of your Create factory method will be evaluated at runtime based on the value of the parameter. Generics are for compile-time safety and in your case you cannot have such safety because the parameter value will be known only at runtime.
I have the following class and extension class (for this example):
public class Person<T>
{
public T Value { get; set; }
}
public static class PersonExt
{
public static void Process<TResult>(this Person<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
I was expecting I could write something like the following and it would work, but it doesn't:
var x = new Person<List<String>>();
x.Process();
Since List is lower in the inheritance tree than IEnumerable, shouldn't this be valid? It works if I new up a Person<IEnumerable<String>> of course because that's the direct type.
I'm trying to use an extension method that can be applied to all Person<T>'s as long as T implements IEnumerable<Something> because I need to use the .Any() method.
EDIT: Maybe my understanding of covariance is off? I know IEnumerable<String> should convert to IEnumerable<Object>, but couldn't IList<String> convert to IEnumerable<String>?
EDIT2: Forgot to mention that I am using .net 4.0.
I know IEnumerable<String> should
convert to IEnumerable<Object>, but
couldn't IList<String> convert to
IEnumerable<String>?
IList<String> can convert to IEnumerable<String>. The problem is that you're trying to convert Person<List<String>> to Person<IEnumerable<String>>, which is illegal. For example, it's perfectly valid to write:
var x = new Person<IEnumerable<String>>();
x.Value = new string[0];
since Value is of type IEnumerable<String> and a string array is an IEnumerable<String>. However, you cannot write:
var x = new Person<List<String>>();
x.Value = new string[0];
since Value is of type List<String>. Since you can't use a Person<List<String>> in all places where you could use a Person<IEnumerable<String>>, it's not a legal cast.
Note that you can do something similar to what you want if you add a second type parameter to your extension method:
public static void Process<TResult, TList>(this Person<TList> p)
where TList : IEnumerable<TResult>
{
Console.WriteLine(p.Value.Any());
}
Unfortunately, the compiler won't be able to infer both type parameters, so you would have to call it like this:
var x = new Person<List<String>>();
x.Process<String, List<String>>();
If you are using C# 4.0 and can use covariance, then you can define a covariant interface for person:
public interface IPerson<out T>
{
T Value { get; }
}
public class Person<T>
: IPerson<T>
{
public T Value { get; set; }
}
And then write your extension method as:
public static void Process<TResult>(this IPerson<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
Since IPerson<T>.Value is read-only, a IPerson<List<String>> can be used everywhere that an IPerson<IEnumerable<String>> can be, and the conversion is valid.
I'm not sure you've quite grasped the correct use of generics. In any event ...
The only thing that is incorrect is your declaration of extension method, and the way you are attempting to constrain the extension method.
public static class ThingExtensions
{
public static void Process<T>(this Thing<T> p)
where T : IEnumerable<string>
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
All I've really done is rename Person to Thing so that we're not getting hung up on what a Person<List<string>> really is.
public class Thing<T>
{
public T Value { get; set; }
}
class ListOfString : List<string>
{ }
class Program
{
static void Main(string[] args)
{
var x = new Thing<ListOfString>();
x.Value = new ListOfString();
x.Process();
x.Value.Add("asd");
x.Process();
var x2 = new Thing<int>();
// Error 1 The type 'int' cannot be used as type parameter 'T'
// in the generic type or method
// 'ThingExtensions.Process<T>(Thing<T>)'.
// There is no boxing conversion from 'int' to
// 'System.Collections.Generic.IEnumerable<string>'.
//x2.Process();
Console.Read();
}
}
You could also move the generic constraint to the Thing<T> if that was more applicable.
You mention covariance, but don't actually use it. You have to specify in or out on your generic parameters. Note that co/contravariance doesn't work on class types; they must be applied to interfaces.
So, introducing an interface and making it covariant:
public interface IPerson<out T>
{
T Value { get; }
}
public class Person<T> : IPerson<T>
{
public T Value { get; set; }
}
public static class PersonExt
{
public static void Process<TResult>(this IPerson<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
allows this code to compile:
var x = new Person<List<String>>();
x.Process();