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();
Related
I have a generic method like this (simplified version):
public static TResult PartialInference<T, TResult>(Func<T, TResult> action, object param)
{
return action((T)param);
}
In the above, param is of type object on purpose. This is part of the requirement.
When I fill in the types, I can call it like this:
var test1 = PartialInference<string, bool>(
p => p.EndsWith("!"), "Hello world!"
);
However, I'd like to use type inference. Preferably, I would like to write this:
var test2 = PartialInference<string>(
p => p.EndsWith("!"), "Hello world!"
);
But this does not compile. The best I came up with is this:
var test3 = PartialInference(
(string p) => p.EndsWith("!"), "Hello world!"
);
The reason I would like to have this as a type parameter and still have the correctly typed return type is because my actual calls look something like this:
var list1 = ComponentProvider.Perform(
(ITruckSchedule_StaffRepository p) => p.GetAllForTruckSchedule(this)
)
Which is very ugly and I would love to write as something like this:
var list2 = ComponentProvider.Perform<ITruckSchedule_StaffRepository>(
p => p.GetAllForTruckSchedule(this)
)
You can split t into a generic method on a generic type:
class Foo<TOuter> {
public static void Bar<TInner>(TInner arg) {...}
}
...
int x = 1;
Foo<string>.Bar(x);
Here the int is inferred but the string is explicit.
What you are trying to achieve is not possible. You need to specify both generic arguments or none of the them if inference is possible.
You can use reflection... like this below
Here is an example of how to call a extension method with two generic parameters.
We have to ways to execute the extension method:
a) Directly from an abstract base class
b) From an instance object that derived from that base class
Not mandatory to implement like so, but I found it very handy.
a) You must supply the two generic arguments as usual.
b) You already have one of the generic types since you are using an instance. The other generic parameter must by passed as type argument, you cannot pass it a second generic parameter due to ambiguity.
(see How to pass 2 generics types into an extension method)
public interface IEntityDto
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your generic types don't need interface constraints
}
public interface IRowVersion
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your generic types don't need interface constraints
}
public interface IPropertyMappingValue
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your returned object don't need interface constraints
string Value { get; set; }
}
public class PropertyMappingValue : IPropertyMappingValue
{
// Not relevant to this example, how is defined , is just an object, returned by our extension method
public string Value { get; set; }
}
public abstract class EntityBase
{
public static IPropertyMappingValue GetPropertyMappingValue<TEntity, TEntityDto>(string name) where TEntity : class, IRowVersion where TEntityDto : class, IEntityDto => EntityExtensions.GetPropertyMappingValue<TEntity, TEntityDto>(name);
}
// Sample Class
public class Entity : IRowVersion
{
}
// Sample Class
public class EntityDto : EntityBase, IEntityDto
{
}
public static class EntityExtensions
{
public static IPropertyMappingValue GetPropertyMappingValue<TEntityDto>(this TEntityDto instance, Type entityType, string name) where TEntityDto : class, IEntityDto
{
if (!typeof(IRowVersion).IsAssignableFrom(entityType))
throw new ArgumentException($"{entityType} do not implements {typeof(IRowVersion)}");
var method = typeof(EntityExtensions).GetMethod(nameof(GetPropertyMappingValue), new[] { typeof(string) });
var typeArgs = new[] { entityType, typeof(TEntityDto) };
var constructed = method?.MakeGenericMethod(typeArgs);
var result = constructed?.Invoke(null, new object[] { name });
return result as IPropertyMappingValue;
}
public static IPropertyMappingValue GetPropertyMappingValue<TEntity, TEntityDto>(string name) where TEntity : class, IRowVersion where TEntityDto : class, IEntityDto
{
//TO DO YOUR JOB HERE TO GET A VALID RETURNED OBJECT, as this is an example I will return a fake
// THE CODE IS JUST AN EXAMPLE of doing something with the types, but is not relevant for this example
//
var foo = typeof(TEntityDto);
var bar = typeof(TEntity);
//
return new PropertyMappingValue { Value = name }; // returning just a fake object
}
}
public class UnitTest
{
private readonly ITestOutputHelper _console;
public UnitTest(ITestOutputHelper console)
{
_console = console;
}
[Fact]
public void Test()
{
var oneWayOfExecuting = EntityBase.GetPropertyMappingValue<Entity, EntityDto>("Hello world"); //using a abstract base
_console.WriteLine(oneWayOfExecuting.Value);
var entityDto = new EntityDto();
var anotherWayOfExecuting = entityDto.GetPropertyMappingValue(typeof(Entity), "Hello world"); //using the extension method
_console.WriteLine(anotherWayOfExecuting.Value);
Assert.Equal("Hello world", oneWayOfExecuting.Value);
Assert.Equal("Hello world", oneWayOfExecuting.Value);
}
I have the following types:
public abstract class Game<TRules>
where TRules : new()
{
public TRules Rules { get; set; } = new TRules();
}
public class Cricket : Game<CricketRules>
{
}
public class CricketRules
{
public string SomeRule { get; set; }
}
I also have an extension method that helps set the rules property:
public static class GameExtensions
{
public static void SetRules<TGame, TRules>(this TGame game, Action<TRules> setter)
where TGame : Game<TRules>
where TRules : new()
{
setter(game.Rules);
}
}
and I'm able to call the extension method:
new Cricket().SetRules<Cricket, CricketRules>(r => { r.SomeRule = "rule"; });
but I get an error when I omit specifying the type parameters:
new Cricket().SetRules(r => { r.SomeRule = "rule"; }); // doesn't compile
I'd have expected the extension method to infer both TGame as Cricket and TRules as CricketRules in this case due to the constraint TGame : Game<TRules> on the method.
Is there any way to avoid passing the type parameters explicitly when calling the extension method?
Note: I've seen some SO answers that suggest (for slightly different scenarios) splitting the extension method into two (in different classes) each taking a single type parameter but am not able to figure out a similar approach that would work in this case.
You can specify the type in the lambda:
new Cricket().SetRules((CricketRules r) => { r.SomeRule = "rule"; });
Normally (or rather, almost always) you'd omit the type name. People omit it so often that people forget that you can put the type name there... :)
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 :-)
I have an explicit conversion defined from type Bar to type Foo.
public class Bar
{
public static explicit operator Foo(Bar bar)
{
return new Foo(bar.Gar);
}
}
public class Foo
{
public string Gar { get; set; }
public Foo() { }
public Foo(string gar) { Gar = gar; }
}
However, when I do:
using System.Linq;
...
var manyFoos = manyBars.Cast<Foo>();
It throws an exception saying it can't cast.
How do I tell Cast to use my cast operator to try the conversion?
Cast operators are static methods that the compiler calls when you use casts in code. They cannot be used dynamically. Enumerable.Cast does a runtime cast of two unconstrained generic types, so it cannot know during compile time which cast operators to use. To do what you want, you can use Select:
manyFoos.Select(foo => (Bar)foo);
The linq Cast method essentially does a box and unbox. It is not aware of either implicit or explicit cast operators defined in C#, which the compiler treats standard method calls.
You'd have to do something like this:
var manyFoos = manyBars.Select(bar => (Foo)bar);
As all other answers pointed type is not known in compile time since Cast method is not generic. It holds type of object and makes a explicit cast to T. this fails because you don't have conversion operator from object to Foo. And that is not possible also.
Here is a work around using dynamics in which cast will be done in runtime.
public static class DynamicEnumerable
{
public static IEnumerable<T> DynamicCast<T>(this IEnumerable source)
{
foreach (dynamic current in source)
{
yield return (T)(current);
}
}
}
Then use it like
var result = bars.DynamicCast<Foo>();//this works
Use Select:
var manyFoos = manyBars.Select(bar => (Foo)bar);
Your code doesn't actually compile. I assume that there is a property "Gar" in the "Bar" class as well?
public class Bar
{
public string Gar { get; set; }
public static explicit operator Foo(Bar bar)
{
return new Foo(bar.Gar);
}
}
public class Foo
{
public string Gar { get; set; }
public Foo() { }
public Foo(string gar) { Gar = gar; }
}
static void Main(string[] args)
{
List<Bar> bars = new List<Bar>();
for (int i = 0; i < 10; i++)
bars.Add(new Bar() { Gar = i.ToString() });
var result = bars.Cast<Foo>();
}
+
I encaurage you to read about covariance.
Assuming A is convertible to B, X is covariant if X<A> is convertible to X<B>.
With C#’s notion of covariance (and contravariance), “convertible” means convertible via an implicit reference conversion— such as A subclassing B, or A implementing B. Numeric conversions, boxing conversions, and custom conversions are not included.
You have to do that with interfaces.
I have 2 base classes FirstBase and SecondBase. I also have 2 class derive from them, DerivedFirst and DerivedSecode and both of them has almost of same property. Source code is like below.
public abstract class FirstBase
{
//some method
}
public abstract class SecondBase
{
//some method
}
public class DerivedFirst : FirstBase
{
//override methods of its parent
public static implicit operator DerivedFirst(DerivedSecond second)
{
//doing some logic here
}
}
public class DerivedSecond : SecondBase
{
//override methods of its parent
public static implicit operator DerivedSecond(DerivedFirst first)
{
//doing some logic here
}
}
From this code I can create instance of DerivedFirst and assign to DerivedSecond without any problem. However when I try to convert list of them like code below, It has no result.
List<DerivedFirst> firstList;
List<DerivedSecond> secondList;
//doing some operation here
List<DerivedSecod> test = firstList.Cast<DerivedSecond>(); // don't have any output here.
How can I convert firstList to List()?
User-defined implicit conversions are considered only at compile time, not at run-time (source). You can use Select instead:
List<DerivedSecond> foo = firstList.Select(x => (DerivedSecond)x).ToList();
Your desired behavior does not work. The static implicit operator is nothing more than a fancy way to write code. DerivedFirst cannot really be casted into a DerivedSecond.
The call of FirstList.Cast<DerivedSecond> works since LINQ streams over the input list while accessing its items. As soon as you access any item in the resulting IEnumerable<DerivedSecond> you get an InvalidCastException.
Try this Visual Studio Test code to see what I mean:
[TestClass]
public class UnitTest1 {
class DerivedA {
public static implicit operator DerivedA(DerivedB b) {
return new DerivedA();
}
}
class DerivedB {
public static implicit operator DerivedB(DerivedA a) {
return new DerivedB();
}
}
[TestMethod]
public void TestMethod1() {
IList<DerivedA> lista = new List<DerivedA> {
new DerivedA()
};
var casted = lista.Cast<DerivedB>();
try {
DerivedB b = casted.First();
Assert.Fail();
} catch (InvalidCastException) {
// exception will be thrown
}
}
}
Edit:
The only solution to "cast" the objects is to use the "Select" method:
var casted = lista.Select(a => (DerivedB)a);
You have just talked about Variance. C# actually introduces Co-variance in .NET 4.0. So if you are in C# 4.0, you can easily do this using out operator in your list.
Check my article
http://www.abhisheksur.com/2010/06/c-40-features.html
I hope this would help you.
Otherwise you can use Loop to cast each individual objects to create a separate list of that type.