I'm trying to understand how covariance works with generic type constraints and it seems like the constraints are ignored for no obvious reason.
Consider the following code:
public interface IContainer<out T> { }
public interface IContents { }
public class Food : IContents { }
public class Foo
{
public void Bar<T>() where T : IContents
{
IContainer<IContents> x = null;
IContainer<T> y = null;
IContainer<Food> z = null;
x = y; // Cannot convert source type 'IContainer<T>' to target type 'IContainer<IContents>'
x = z; // Valid
}
}
Why does compiler produce 'Cannot convert' error on x = y and produce no error on x = z?
C# does not support variance for value types - see the variant generic interfaces doc:
ref, in, and out parameters in C# cannot be variant. Value types also do not support variance.
i.e. the following will not work:
public struct MyStruct : IContents
{
}
var structContainer = (IContainer<MyStruct>)null;
IContainer<IContents> x = structContainer;
Since T is not constrained neither to class not to struct it can be either reference type or value type, so in general case IContainer<T> is not assignable to IContainer<IContents>.
Add class constraint to the Bar method:
public class Foo
{
public void Bar<T>() where T : class, IContents
{
IContainer<IContents> x = null;
IContainer<T> y = null;
IContainer<Food> z = null;
x = y; // Now Valid
x = z; // Valid
}
}
Related
imagine a generic class B
public class B<T> : IB
{
public void Foo(object parameter)
{
var param = (T)parameter;
//...
}
}
And a class A, which get's a collection of Bs passed through it's constructor. Notice im using the interface IB as type there.
public class A
{
public A(IEnumerable<IB> collectionOfBs) {}
}
Sometime later, I want to execute some Method on class A, let's say foo, which will take a collection of objects of type T, where T is the generic type of the instance of B passed in the constructor. so these types have to match.
public void foo(IEnumerable<object> param)
{
for (int i = 0; i < collectionOfBs.Count(); i++)
{
collectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
}
}
Right now im passing an IEnumerable<object> and cast to type T inside of foo, that will work but I'm wondering if I could have this type check at compile time instead?
Any Ideas if thats possible or not?
Thanks
You can try this using a generic method for the type of the provided parameter.
It does not ensure that TParam and T are same, since you have a non generic interface, but is it the best you can do, as I know, according to a first study of your problem...
Because there is no diamond operator in C# to allow true generic polymorphism on open types.
public interface IB
{
void Foo<TParam>(TParam parameter);
}
public class B<T> : IB
{
public void Foo<TParam>(TParam parameter)
{
var param = parameter;
Console.WriteLine("param type: " + param.GetType().Name);
}
}
public class A
{
private IEnumerable<IB> CollectionOfBs;
public A(IEnumerable<IB> collectionOfBs)
{
CollectionOfBs = collectionOfBs;
}
public void Foo(IEnumerable<object> param)
{
if ( param.Count() < CollectionOfBs.Count() )
throw new ArgumentException();
for ( int i = 0; i < CollectionOfBs.Count(); i++ )
CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
}
}
Test method
static void Test()
{
var listInstances = new List<IB> { new B<int>(), new B<double>(), new B<string>() };
var container = new A(listInstances);
var listParams = new List<object> { 2, 4.3, "test" };
container.Foo(listParams);
}
Output
param type: Int32
param type: Double
param type: String
Considerations
The problem here is that any bad matching parameter type can be passed.
For example with the Test(), you can have a double instead of the first integer and it works: you get a Double on your Int32 instance...
param type: Double
param type: Double
param type: String
Having the diamond operator <> you will be able to use a generic interface and parse on a closed constructed types list... and your design will have a better smell:
public interface IB<T>
{
void Foo(T parameter);
}
public class B<T> : IB<T>
{
public void Foo(T parameter)
{
var param = parameter;
Console.WriteLine("param type: " + param.GetType().Name);
}
}
public class A
{
private IEnumerable<IB<>> CollectionOfBs;
public A(IEnumerable<IB<>> collectionOfBs)
{
CollectionOfBs = collectionOfBs;
}
public void Foo(IEnumerable<object> param)
{
if ( param.Count() < CollectionOfBs.Count() )
throw new ArgumentException();
for ( int i = 0; i < CollectionOfBs.Count(); i++ )
{
CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
}
}
}
Hence with that, any bad matching type of parameter will raise an exception at runtime.
When you want consistent generic type checking, you need to apply generics consistently. Currently, you are using a half-way approach: B<T> is generic, but IB is not. Then you have a non-generic class A, which couples to the non-generic interface IB, but you want compile-time type checking of T, which both, A and IB know nothing about (only to internally cast it to T). That's a bit of a problem.
From the usage of your classes/interface it seems obvious that you don't expect mixed IB implementations in A, so what you can do is to consistently apply the generic type parameter T on all types:
public class B<T> : IB<T>
{
public void Foo(T parameter)
{
var param = parameter;
//...
}
}
public class A<T>
{
public A(IEnumerable<IB<T>> collectionOfBs) {}
public void foo(IEnumerable<T> param)
{
collectionOfBs.Zip(param, (b, t) => { b.Foo(t); return 0 });
}
}
Note that I replaced your approach with for and ElementAt by Enumerable.Zip.
Following this question, I see it's possible to pass a type to a method. Inside the method to which the type has been passed, how would an object be cast to that passed type? As a complication, class Foo inherits from a class which I cannot change.
var x = FetchData();
Foo foo = new Foo(2, typeof(Gizmo)); // pass the Gizmo type
foo.Execute(x);
public class Foo : ThirdPartyLibrary.Operation
{
Type customtype;
public Foo(int i, Type passedtype) : base()
{
this.customtype=passedtype;
}
public override void Execute(ThirdPartyLibrary.Node node)
{
var record = ( ??? ) node.GetData(); // cast node to the type of customtype
}
}
If I'm understanding your question correctly, you can do this with generics. It would look something like this (based off your example code):
public class Foo<T> : ThirdPartyLibrary.Operation
{
public Foo(int i) : base()
{
//hopefully you actually do something useful with "i" here.
}
public override void Execute(ThirdPartyLibrary.Node node)
{
//I'm not 100% sure which object you are trying to cast, so I'm showing both forms below. You obviously won't be able to do both without changing the variable name.
//If you want to cast the "Data", use this.
var record = (T) node.GetData();
//If you want to cast "node", use this.
var record = ((T) node).GetData();
}
}
You use it this way:
var x = FetchData();
Foo foo = new Foo<Gizmo>(2);
foo.Execute(x);
customtype is no longer required, as you can access to the Type of T with typeof(T) from anywhere within the class.
A challenge with a colleague about if there is any way to cast a struct to a class here the example that we have tried
namespace ConsoleApplication22
{
class Program
{
static void Main(string[] args)
{
IFoo fooS = new FooStruct();
fooS.Val = 5;
FooClass foo =(FooClass) fooS;
}
}
public interface IFoo
{
int Val { get; set; }
}
public struct FooStruct : IFoo
{
public int Val { get; set; }
}
public class FooClass : IFoo
{
//public FooClass(int val)
//{
//}
private int val;
public int Val
{
get { return val; }
set { val = value; }
}
}
}
but we got an invalid cast exception :D
are there any tricky way to extract the interface and assign it to the class given that an interface is a reference type and a class is a reference type and the class implements the interface
You cannot directly cast between the two via the interface, it isn't allowed because they are not related to each other directly (ie, inheritance).
The compiler can catch a lot of this type of thing and not even allow the cast to compile. If the compiler cannot do it, the runtime does it. For explicit casting, the runtime will throw an exception on failed casts, for attempts at implicit casting (reference types only) the runtime returns null and does not throw an exception.
The type checking actually checks that FooStruct is a FooClass, which it can't be.
However, you can use the casting operators to convert between them making it look like a cast
class Program
{
static void Main(string[] args)
{
FooStruct f = new FooStruct();
f.Val = 2;
FooClass f2 = (FooClass)f;
Console.Read();
}
}
class FooClass : IFoo
{
public static explicit operator FooClass(FooStruct f)
{
FooClass foo = new FooClass();
foo.Val = f.Val;
return foo;
}
public int Val { get; set; }
}
struct FooStruct : IFoo
{
public int Val { get; set; }
public static explicit operator FooStruct(FooClass f)
{
FooStruct foo = new FooStruct();
foo.Val = f.Val;
return foo;
}
}
// This interface has little use in this scenario.
interface IFoo
{
int Val { get; set; }
}
Don't confuse casting with conversion. Also, be wary of applying interfaces to struct types because boxing can occur.
No.
Create a copy method to your FooClass that takes instance of IFoo, and perform necessary copy there.
The most hackish way I could think of (and one you should never, ever use!) is through the use of the Marshal:
public unsafe static TDest UnsafeCast<TDest, TSrc>(object source)
{
byte[] buffer = new byte[Marshal.SizeOf(typeof(TSrc))];
fixed (byte* b = buffer)
Marshal.StructureToPtr(source, new IntPtr(b), true);
fixed (byte* b = buffer)
return (TDest) Marshal.PtrToStructure(new IntPtr(b), typeof (TDest));
}
This literally marshals the data kept in FooClass to FooStruct, which allows it to be "cast" from a reference type to a value type.
You could optionally skip the second marshal if you use the FooStruct type rather than a generic type parameter, by casting the buffer to the FooStruct type from the buffer directly:
fixed (byte* b = buffer)
{
var s = (FooStruct*) b;
return *s;
}
Requires unsafe compiler option, and should never ever be done in any sort of production environment - it's very slow and unpredictable.
I got a question for some code:
interface IDistance<T>
{
double distance();
double distance(T obj);
}
class Point<T> where T : IDistance<T> //why do i need this?
{
T obj;
public double dist(T val) { return obj.distance(val);
public Point(T obj) { this.obj = obj; }
}
class P2D : IDistance<P2D>
{
public double[] x = new double[2];
public P2D(double x, double y)
{
this.x[0] = x; this.x[1] = y;
}
public double distance()
{
double d = 0.0;
for (int i = 0; i < 2; i++) d = d + x[i] * x[i];
return Math.Sqrt(d);
}
public double distance(P2D val)
{
double d = 0.0;
for (int i = 0; i < 2; i++) d = d + Math.Pow(x[i]-val.x[i],2);
return Math.Sqrt(d);
}
}
class Tester
{
static void Main(string[] args)
{
P2D P1 = new P2D(3.0, 4.0);
Point<P2D> C1 = new Point<P2D>(P1);
Console.WriteLine(C1.dist());
}
}
The code in detail is rather unimportant.
Why do I need the constrain where T : IDistance<T> in the generic class Point<T>?
When I only specify classes that already implemented the interface IDistance<T> like
Class P2D, shouldn't be the interface already implemented implicit in the class Point?
I get the fact that it can cause problems, when a class as type <T> in class Point is defined that has not implemented the interface. But in this case, why is it not possible?
Look at this code within Point<T>:
T obj;
public double dist(T val) { return obj.distance(val);
When the compiler tries to understand what this expression means:
obj.distance(val)
it has to resolve the distance member. If T is unconstrained, it can't do that. When T is constrained to implement IDistance<T>, it can - it resolves it to the member of the interface.
In particular, without the constraint, I could use the type in very odd ways:
Point<string> weird = new Point<string>("foo");
double result = weird.dist("bar");
What would you expect that to do?
(As a side note, it would be worth following normal .NET naming conventions, even for examples. Methods should be PascalCased, and I'd never call a class P2D...)
When I only specify classes that already implemented the interface IDistance like Class P2D, shouldnt be the interface already implemented implicit in the Class Point? I get the fact that it can cause problems, when a class as type in Class Point is defined that has not implemented the interface. But in this case, why is it not possible?
Because C# is a language that has compile-time type safety. Without that constraint, you may only ever instantiate Point<T> with values of T at run-time which implement IDistance<T>, but there's no way for the compiler to know at compile-time that you will be so well-behaved.
why do i need this?
You need the constraint because you are restricting the generic type to be an implementation of the interface, IDistance<T>. If Point class you use some methods from this type like obj.distance(val);.
You also could use a abstract class to restrict derivations. Take a look at documentation in MSDN.
http://msdn.microsoft.com/en-us/library/bb384067.aspx
class Point<T> where T : IDistance<T> //why do i need this?
You need this becuase the class you declare, should take as type a type that implements the interface called IDistance<T>
I have a base class Base, and class A/B that inherits from it.
public class Base
{
int x;
}
public class A : Base
{
int y;
}
public class B : Base
{
int z;
}
I tried to use OfType to filter the only object that I need as follows:
public static void RunSnippet()
{
Base xbase; A a; B b;
IEnumerable<Base> list = new List<Base>() {xbase, a, b};
Base f = list.OfType<A>; // I need to get only the object A
Console.WriteLine(f);
}
When I compiled the code, I got this error:
error CS0428: Cannot convert method group 'OfType' to non-delegate type 'Base'. Did you intend
to invoke the method?
What's wrong with the code?
There are two problems:
OfType returns IEnumerable<T>, not T
It's a method - you forgot the brackets
Perhaps you wanted:
Base f = list.OfType<A>().FirstOrDefault();
?
Brackets ?
This is a function and not operator.
Base f = list.OfType<A>()
Check out the reference:
Enumerable.OfType(Of TResult) Method