How to use the Covariance(out keyword)?I have no idea.
I know out keyword in Interface mean Covariance that allow you use a more derived type than that specified by the generic parameter.
So i set generic to object and return type to string.Because string is subclass of object.
But i tried and it not working.
public interface IMyInterface<out T>
{
public T Foo();
}
public class CovarianceTest : IMyInterface<object>
{
public string Foo()
{
return "abc";
}
}
Covariance that allow you use a more derived type than that specified by the generic parameter
That's not what it means. You still have to write methods that match the types in the interface. So you will have to do this:
public class CovarianceTest : IMyInterface<string>
{
public string Foo()
{
return "abc";
}
}
What covariance allow you to do is assign the class instance to a variable typed as a less specific interface, like this:
IMyInterface<object> x = new CovarianceTest();
Console.WriteLine(x.Foo());
That's because all Ts read from the interface (i.e. taken out) are guaranteed to be instances that are type-compatible with the less specific type, i.e. all strings are also objects.
I suspect you are trying to do the following.
public interface IMyInterface<out T>
{
public T Foo();
}
public class CovarianceTest : IMyInterface<string>
{
public string Foo()
{
return "abc";
}
}
IMyInterface<string> works = new CovarianceTest();
IMyInterface<object> alsoWorks = new CovarianceTest();
IMyInterface<int> doesNotWork = new CovarianceTest();
Related
I'm attempting to write a generic method based on the following myMethod:
void myMethod(myClassA instanceA, myClassB instanceB)
{
instanceA = new myClassA(instanceB);
}
What I've got so far is something like this (myMethod_new), which has some errors:
void myMethod_new<S, T>(S instanceA, T instanceB) where S : new()
{
instanceA = new S(instanceB);
}
However, since I've not mastered how generics work in C#, how should this be implemented?
You can't create a new instance of a generic type if the type has parameters in the constructor. From the docs (emphasis mine):
The new constraint specifies that a type argument in a generic class declaration must have a public parameterless constructor.
One option is to use Activator.CreateInstance and pass in the parameter(s) required. However, that can lead to runtime exceptions since the caller could pass in any type with any format of constructor.
My advice would be to refactor slightly by removing the constructor parameter and create a method to pass that value in, then use an interface to contstrain it all. For example:
// The interface
public interface IHasThing<T>
{
void SetThing(T value);
}
// An implementation of the interface
public class Foo : IHasThing<string>
{
private string _value;
public void SetThing(string value)
{
_value = value;
}
}
And your updated method that returns the new object:
public S myMethod_new<S, T>(T instanceB) where S : IHasThing<T>, new()
{
var s = new S();
s.SetThing(instanceB);
return s;
}
So now you can call the method like this:
var foo = myMethod_new<Foo, string>("bar");
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 code like this:
class Base { }
class Derived : Base { }
class Wrapper<T> {
public T Value { get; }
public Wrapper (T value) { Value = value; }
}
I would like to use Wrapper like this:
Wrapper<Base> wrapper = new Wrapper<Derived> (new Derived ());
But it ends up with this error:
Error CS0029 Cannot implicitly convert type 'Wrapper<Derived>' to 'Wrapper<Base>'
I tried creating method in Wrapper class that would act as converter
public Wrapper<TResult> To<TResult> () /* Constraints needed here. */ =>
new Wrapper<TResult> (Value);
But I'm missing some valid constraints. Current code ends up with error:
S1503 Argument 1: cannot convert from 'T' to 'TResult'
I would imagine constraints on To method could look like where T : TResult, but that's not valid constraints.
Any ways to implement converter from Wrapper<Derived> to Wrapper<Base> easily?
You could use covariance like so:
class Base { }
class Derived : Base { }
interface IWrapper<out T>
{
T Value { get; }
}
class Wrapper<T> : IWrapper<T>
{
public T Value { get; private set; }
public Wrapper(T value) { Value = value; }
}
class Program
{
static void Main(string[] args)
{
IWrapper<Base> wrapper = new Wrapper<Derived>(new Derived());
}
}
At first I would add a constraint to the class demanding that T must be of type Base:
class Base { }
class Derived : Base { }
class Wrapper<T> where T : Base // T must be (derived from) Base
{
public T Value { get; }
public Wrapper (T value) { Value = value; }
}
Secondly, a generic converter would be dangerous. What if someone tries to convert a Wrapper<Gnu> to a Wrapper<Lion>?
So I'd take a step back and make a non-generic converter that simply converts to Wrapper<Base>:
public Wrapper<Base> ToBase()
{
return new Wrapper<Base>(Value);
}
And this works because of the constraint for T at class level.
C# is actually a language known for a high level of type safety. But you can get around it and do what you asked for in the comment by ommitting any constraints and just trying to cast whatever comes in:
public Wrapper<TResult> To<TResult>() where TResult : class
{
return new Wrapper<TResult>(Value as TResult);
}
You need the class constraint and the as operator because a direct cast between two generic parameters is not compilable (as the IL depends too much on the specific types).
But this will return Wrapper instances with Value set to null if the types don't match. And it will work with derived types instead of base types too. So take care. You may add some extra checks for that. And take care of the gnus :)
UPDATE:
A safer way:
public Wrapper<TResult> To<TResult>() where TResult : class// TResult must also be (derived from) Base
{
if (!typeof(TResult).IsAssignableFrom(typeof(T)))
throw new InvalidCastException();
return new Wrapper<TResult>(Value as TResult);
}
This checks that T is derived from TResult and throws an InvalidCastException if not. You may refine that for your needs.
The problem you're encountering is that the generic types Wrapper<Base> and Wrapper<Derived> are two completely different classes for the .NET Framework
What you could do is creating a new Wrapper of type Base:
Wrapper<Base> wrapper = new Wrapper<Base>(new Derived());
Or to complete your To-method approach:
public Wrapper<TResult> To<TResult>() where TResult : T
=> new Wrapper<TResult>( (TResult)Value ); // This could throw an error
public bool TryCastTo<TResult>(out Wrapper<TResult> derivedWrapper) where TResult : T
{
derivedWrapper = null;
// EDIT: changed to the version from René Vogt since this is much cleaner and mine had a little error
if (!typeof(T).IsAssignableFrom(typeof(TResult)))
{
return false;
}
derivedWrapper = new Wrapper<TResult>( (TResult)Value );
return true;
}
The usage would be:
Wrapper<Derived> derivedWrapper1 = wrapper.To<Derived>();
Wrapper<Derived> derivedWrapper2;
bool success = wrapper.TryCastTo<Derived>(out derivedWrapper2);
I want to specify required default constructrion options for my T:
public interface IParameter<T> /* where T : T(string) */ {
T Value { get; set; }
}
so I would be able to construct it from given string if passible like this:
Value = "bla";
or at least like this:
Value = new T("bla");
So how to specify in C# generics such T that is constructible from string?
Unfortunately, that constraint is not legal. Only the parameterless constructor constraint is allowed:
where T : new()
Unfortunately, C# does not offer arbitrary constructor signature restrictions for generic parameters. Only a restricted number of constraints are supported, the closest one of which is the new constraint. However, it serves only for enforcing a parameterless constructor.
You can, however, work around this drawback by working with a factory object that takes a string and returns a T. First, define an interface for such factory objects:
public interface IFactory<T>
{
T Create(string str);
}
Subsequently, you can use that factory type in your interface:
public interface IParameter<TFactory, T>
where TFactory : IFactory<T>
{
T Value { get; set; }
}
If you want to be able to instantiate the factories at will, you can require them to have a parameterless constructor:
public interface IParameter<TFactory, T>
where TFactory : new(), IFactory<T>
{
T Value { get; set; }
}
Then, you could use a generic method to instantiate a T based on a string, e.g. as an extension method for your interface:
public static class ParameterUtilities
{
public static void AssignValue<TFactory, T>(this IParameter<TFactory, T> prm, string str)
where TFactory : new(), IFactory<T>
{
var factory = new TFactory();
prm.Value = factory.Create(str);
}
}
As an example of how to use this, let's assume the variable myPrm is an instance of that implements your IParameter interface with appropriate type arguments. You can then invoke something like this:
myPrm.AssignValue("Hello, World!");
You can't, because in generic type constraints you can't say that the type must have a specific constructor (only that it must have a parameterless constructor) nor say that it must have specific methods/operators.
BUT
public interface IFromString<T>
{
void DeserializeFromString(string str);
}
public class MyType : IFromString<MyType>
{
public int Value;
public void DeserializeFromString(string str)
{
Value = int.Parse(str);
}
}
public interface IParameter<T> where T : IFromString<T>, new()
{
T Value { get; set; }
}
public class Parameter<T> : IParameter<T> where T : IFromString<T>, new()
{
T Value { get; set; }
public void Load(string str)
{
Value = new T();
Value.DeserializeFromString(str);
}
}
A classical example... an interface that says that a type can be deserialized from (something) (xml very often :-) )
Use:
Parameter<MyType> parameter = new Parameter<MyType>();
parameter.Load(someStringLoadedFromSomewhere);
You can't specify a constructor in an interface. Depending on your requirements you could use an abstract class:
Pseudo code as not at machine with VS:
public abstract class BaseParameter<T>
{
public abstract void BaseParameter(string something);
T Value { get; set; }
}
Suppose I write a library with the following:
public class Bar { /* ... */ }
public class SomeWeirdClass<T>
where T : ???
{
public T BarMaker(Bar b)
{
// ... play with b
T t = (T)b
return (T) b;
}
}
Later, I expect users to use my library by defining their own types which are convertible to Bar and using the SomeWeirdClass 'factory'.
public class Foo
{
public static explicit operator Foo(Bar f)
{
return new Bar();
}
}
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
Foo f = weird.BarMaker(b);
}
}
this will compile if i set where T : Foo but the problem is that I don't know about Foo at the library's compile time, and I actually want something more like where T : some class that can be instantiated, given a Bar
Is this possible? From my limited knowledge it does not seem to be, but the ingenuity of the .NET framework and its users always surprises me...
This may or not be related to the idea of static interface methods - at least, I can see the value in being able to specify the presence of factory methods to create objects (similar to the same way that you can already perform where T : new())
edit: Solution - thanks to Nick and bzIm - For other readers I'll provide a completed solution as I understand it:
edit2: This solution requires Foo to expose a public default constructor. For an even stupider better solution that does not require this see the very bottom of this post.
public class Bar {}
public class SomeWeirdClass<T>
where T : IConvertibleFromBar<T>, new()
{
public T BarMaker(Bar b)
{
T t = new T();
t.Convert(b);
return t;
}
}
public interface IConvertibleFromBar<T>
{
T Convert(Bar b);
}
public class Foo : IConvertibleFromBar<Foo>
{
public static explicit operator Foo(Bar f)
{
return null;
}
public Foo Convert(Bar b)
{
return (Foo) b;
}
}
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
Foo f = weird.BarMaker(b);
}
}
edit2: Solution 2: Create a type convertor factory to use:
#region library defined code
public class Bar {}
public class SomeWeirdClass<T, TFactory>
where TFactory : IConvertorFactory<Bar, T>, new()
{
private static TFactory convertor = new TFactory();
public T BarMaker(Bar b)
{
return convertor.Convert(b);
}
}
public interface IConvertorFactory<TFrom, TTo>
{
TTo Convert(TFrom from);
}
#endregion
#region user defined code
public class BarToFooConvertor : IConvertorFactory<Bar, Foo>
{
public Foo Convert(Bar from)
{
return (Foo) from;
}
}
public class Foo
{
public Foo(int a) {}
public static explicit operator Foo(Bar f)
{
return null;
}
public Foo Convert(Bar b)
{
return (Foo) b;
}
}
#endregion
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo, BarToFooConvertor> weird = new SomeWeirdClass<Foo, BarToFooConvertor>();
Foo f = weird.BarMaker(b);
}
}
Sounds like you found a solution to the larger problem. To answer your specific question: no, neither C# nor the CLR support the "backwards" generic type parameter constraint. That is,
class C<T> where Foo : T
"T must be Foo or a type which Foo converts to" is not supported.
There are languages that have that sort of constraint; IIRC Scala is such a language. I suspect this feature would be handy for certain uses of contravariant interfaces.
I don't think there is necessarily a syntactically cool way to do this built into the language. One possible solution to your problem could be to define a convertible interface:
public interface IConvertible<T>
where T : new() // Probably will need this
{
T Convert();
}
Then your class could be:
public class Foo : IConvertible<Bar>
{
}
I think this gets you close to where you want to be... All the Foo's and Bar's in your question sometimes make it hard to determine exactly what your intent is. Hope this helps.
Edit: Added where constraint... you will probably have to be able to create a new instance in your convertible class.
Edit 2: Made Foo inherit from ICovertible<Bar>
You could make a detour via an interface which is used as a type constraint.
For example, where T : IComparable<U> is used to constrain the type to something that can be compared to another thing, which must express this ability by implementing IComparable<another>. If you had an interface ICastableFrom<T>, you could achieve what you want by forcing them to implement ICastableFrom<Bar>.
Rather than go through the trouble of defining an interface and modifying your class to implement that interface, why not just do this?
public class SomeWeirdClass<T>
{
// aside: why is this method called 'BarMaker' if it returns a T?
public T BarMaker(Bar b, Func<Bar, T> converter)
{
// ... play with b
return converter(b);
}
}
Then in the event that you are dealing with an object of a type T to which Bar can be directly cast, this method could be called simply as follows:
var someWeirdObject = new SomeWeirdClass<Foo>();
var someBar = new Bar();
var someFoo = someWeirdObjcet.BarMaker(someBar, bar => bar as Foo);
By the way (since the Func<T, TResult> delegate emerged in .NET 3.5), you could also use Converter<TInput, TOutput> (which is exactly the same) for the converter parameter.