Tuple literals in interface declarations - c#

So yay for Tuples! I know I can return multiple values from a method with tuples and name them so they don't have to be Item1, Item2, etc.
I can go var results = (result1: r1, result2: r2);
But how do you use tuple literals in an interface declaration such as this?
public interface IFoo {
(T1, T2) Bar();
}
Tried doing (result1: T1, result2: t2) Bar(); but it doesn't work. Is there a way of returning a named tuple from an interface method?

Your syntax for named tuples as a method return type is incorrect:
public interface IFoo {
(T1 result1, T2 result2) Bar();
}
Note: This is because your return type defines the type and name, while assigning names of a tuple literal defines the value and name.
// Method return syntax. Type & Name
public (bool success, T payload) TryGetPayload<T>() { }
// Literal assignment syntax. Name & Value
var result = (success: true, payload: t);

You can't use "literals" to any interface like that, unless as return values for concrete methods.
You can, however, use types. If your T1 and T2 are meant to be generic, you can use Ivan Stoev's comment on the question:
public interface IFoo<T1, T2> {
(T1, T2) Bar();
}
If your T1 and T2 are meant to be concrete, you can use them directly, as mentioned in Neil's answer:
public interface IFoo<T1, T2> {
(int, string) Bar();
}
You can also name them, if you want:
public interface IFoo<T1, T2> {
(T1 theLeft, T2 theRight) Bar();
}
or
public interface IFoo<T1, T2> {
(int theNumber, string theName) Bar();
}

Related

How I can compare two values of same generic type?

Following code won't compile:
class Test<T> where T : class, IComparable
{
public bool IsGreater(T t1, T t2)
{
return t1 > t2; // Cannot apply operator '>' to operands of type 'T' and 'T'
}
}
How I can make it work? I want it to work for T = int, double, DateTime, etc.
The IComparable interface that you have used here as the type constraint gives you a CompareTo method. So you can do something like this:
public bool IsGreater(T t1, T t2)
{
return t1.CompareTo(t2) > 0;
}
While currently you can't do exactly that (and you need to use solution by #DavidG) there is a preview feature you can enable called generic math which is based on static abstract interface members and ships with interface specially for that purpose:
[RequiresPreviewFeatures]
public interface IComparisonOperators<TSelf, TOther> : IComparable, IComparable<TOther>, IEqualityOperators<TSelf, TOther>, IEquatable<TOther> where TSelf : IComparisonOperators<TSelf, TOther>
{
static bool operator <(TSelf left, TOther right);
static bool operator <=(TSelf left, TOther right);
static bool operator >(TSelf left, TOther right);
static bool operator >=(TSelf left, TOther right);
}
So in future (or right now if you want to be an early adopter) you will be able to do (if no major overhaul comes for this preview):
class Test<T> where T : IComparisonOperators<T, T>
{
public bool IsGreater(T t1, T t2)
{
return t1 > t2;
}
}
Note that for Test to support int, double, DateTime, etc. you need to remove class constraint (with or without this preview feature).
You can use this to compare two values of same generic type.
public bool IsGreater(T t1, T t2)
{
return t1.CompareTo(t2) > 0;
}

Inferring only one type with multiple generic types [duplicate]

This question already has answers here:
C# Generic Type Inference With Multiple Types
(2 answers)
Closed 1 year ago.
I have a generic method, defined like this:
public static A Test<A, B>(B b)
where A : new()
{
return new A();
}
I would like to be able to call it something like this:
int result = Test<int>(5.0);
Instead of like this:
int result = Test<int, double>(5.0);
Clearly, the language syntax does not allow for something like that. I'm looking for a simple way to do this, since the B type, in my case, will generally be something long and I would like to avoid long lines of code that are basically just method calls.
Something like this is doable, but ugly:
A Test<A, B>(B b, A placeholder) where A : new() => new A(); // Definition
int result = Test(5.0, 2); // Method call
Are there any other suggestions for doing this?
As per #Damien_The_Unbeliever's comment-reply, C#'s type-inference does not support partial inference - either all parameters (and the return-type, if applicable) must be inferred from the call-site - or you must manually specify all type-parameters.
There are workarounds for many cases though:
Static methods with possibly-inferred type arguments:
If you have a static factory method in a generic class you can move the method to a static class and move the parent class' type-argument to the method if it can be inferred:
public class Foo<T>
{
public static Bar CreateBar( T item )
{
// ...
}
}
Example call-site:
Bar bar = Foo<Coffee>.Bar( starbucks );
Alternative:
public static class Foo
{
public static Bar CreateBar<T>( T item )
{
// ...
}
}
Example call-site:
Bar bar = Foo.Bar( starbucks ); // voila, type-inference!
Methods with non-inferable type arguments:
Methods that have type arguments that cannot be inferred from the call-site could be converted to new generic methods that have partial parameter application, like so:
Consider:
class Foo<TClass>
{
public TReturn DoSomething<TParam,TUnused,TReturn>( TParam p )
{
// ...
}
}
Example call-site:
Violin stradivarius = ...
Woodwind flute = new Foo<Orchestra>().DoSomething<Violin,Percussion,Woodwind>( stradivarius ); // `Violin` was required and couldn't be inferred.
However, we can wrap this DoSomething method in another method-call where some type-arguments are already supplied by a parent context, such as the parent class's type arguments or as type arguments to a class' static methods with only types for parameters that can be inferred.
So, you can sort-of partially-apply these generic types with Func<>, like so:
class PAReturn<TReturn>
{
public static TReturn Invoke( Func<TReturn> func ) => func();
public static TReturn Invoke<T0>( Func<T0,TReturn> func, T0 arg ) => func( arg );
public static TReturn Invoke<T0,T1>( Func<T0,T1,TReturn> func, T0 arg, T1 arg1 ) => func( arg, arg1 );
public static TReturn Invoke<T0,T1,T2>( Func<T0,T1,T2,TReturn> func, T0 arg, T1 arg1, T2 arg2 ) => func( arg, arg1, arg2 );
// etc
}
class PAReturn<TReturn,T0>
{
public static TReturn Invoke( Func<T0,TReturn> func, T0 arg ) => func( arg );
public static TReturn Invoke<T1>(Func<T0, T1, TReturn> func, T0 arg, T1 arg1) => func(arg, arg1);
public static TReturn Invoke<T1,T2>(Func<T0, T1, T2, TReturn> func, T0 arg, T1 arg1, T2 arg2) => func( arg, arg1, arg2 );
}
Example call-site:
Violin stradivarius = ...
Woodwind flute = PartialAply<Percussion,Woodwind>( new Foo<Orchestra>().DoSomething )( stradivarius ); // Observe that `Violin` was inferred.
Unused parameters:
Another trick is to take advantage of how type inference works best for parameters by creating overloads with unused out parameters which can be specified using C# 7.0's ability to make declarations inside out parameter arguments in call-sites and how variables/parameters named _ are discarded:
class Foo<A>
{
// Original method:
public B GetSomething<B,C,D>( C paramC )
{
// ...
}
}
Example call-site:
Cat bagheera = ...
Mouse m = new Foo<Flea>().GetSomething<Mouse,Cat,Dog>( bagheera ); // `Cat` was not inferred.
Like so:
partial class Foo<A>
{
// Inference helper overload:
public B GetSomething<B,C,D>( out B b, out D d, C c)
{
return this.GetSomething<B,C,D>( c );
}
}
Example call-site:
Cat bagheera = ...
Mouse m = new Foo<Flea>().GetSomething( out Mouse _, out Dog _, bagheera ); // `Cat` was inferred.
Combined:
This can be combined with new delegate definitions with out parameters for non-inferable type parameters (because we can't use Func<> because it doesn't list any out parameters):
delegate TReturn PAFunc<TReturn>( out Return _ );
delegate TReturn PAFunc<T0,TReturn>( out Return _, T0 arg0 );
delegate TReturn PAFunc<T0,T1,TReturn>( out Return _, T0 arg0, T1 arg1 );
delegate TReturn PAFunc<T0,T1,N0,TReturn>( out Return _, out N0 _, T0 arg0 ); // `N0` refers to which one is non-inferrable
// etc...
You cant really and here is why....given the below which works, now if you wanted to make b inferred....
public class MyFancyClass
{
}
public static class Test
{
public static A Method<A>(**string b**) where A : new()
{
return new A();
}
}
static async Task Main(string[] args)
{
var result = Test.Method<MyFancyClass>("5.0");
}
if you changed **string b** to be type inferred you would get back what you had.
as if you want to omit the type then how would the compiler know the type.
you could do (not suggesting just saying)
public static A Method<A>(**object**) where A : new()
{
return new A();
}
but again you wouldn't know its type, so you would then need to check
to unbox it to its type.
if( b is string)
{
}
else if(b is int)
{
}
else if (b is double)
{
}
.... and continue.
like
public static class Test
{
public static A Method<A>(object b) where A : new()
{
if (b is string)
{
}
else if (b is int)
{
}
else if (b is double)
{
}
return new A();
}
}

Return multiple types with Tuple<T1,T2>

I need a static function like this :
public static class Output
{
public static Tuple<T1, T2> Output(T1 out1, T2 out2)
{
return new Tuple<T1, T2>(out1,out2);
}
}
But the function has syntax errors. Anyone can help?
NOTE I mean :
retun Output("asd", 10);
return Output(myclassInstance, date);
... instead of below
return new Tuple<string, int>("asd", 10);
return new Tuple<Myclass, DateTime>(myclassInstance, date);
You need to make the method generic:
public static Tuple<T1, T2> YourMethod<T1, T2>(T1 out1, T2 out2)
{
return new Tuple<T1, T2>(out1,out2);
}
However... all of this is just the Tuple.Create method-group - so:
return YourMethod("asd", 10);
is the same as:
return Tuple.Create("asd", 10);
As a side note, you might want to consider ValueTuple<...> (https://www.nuget.org/packages/System.ValueTuple/). In addition to being more efficient, there is inbuilt language support in latest language versions. See https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/#user-content-tuples
The method must not have the same name as the class.
The method needs to be generic (have type parameters)
public static Tuple<T1, T2> Output<T1, T2>(T1 out1, T2 out2)
Since you're using C#7 (according to your tags), you might want to consider doing it like this:
public static (T1 out1, T2 out2) Output<T1, T2>(T1 out1, T2 out2)
{
return (out1, out2);
}
In this case it seems likely that you can give the tuple elements better names than out1 and out2.
However, at this point it seems even more likely that you could forego this wrapper method altogether, and just use the C#7 "Tuple Return" language feature directly where you need it.
There is such builtin function (https://referencesource.microsoft.com/#mscorlib/system/tuple.cs,9124c4bea9ab0199):
public static Tuple<T1, T2> Create<T1, T2>(T1 item1, T2 item2)
{
return new Tuple<T1, T2>(item1, item2);
}

Constrain type parameter to a base type

I know how to force a type parameter to be a subtype of another type:
public interface IMapping<T2>
{
public void Serialize<T3>(T3 obj)
where T3 : T2;
}
...
var mapping = MapManager.Find<Truck>();
mapping.Serialize(new TonkaTruck());
Is there a way to force a type parameter to be a supertype of another type?
public interface IMapping<T2>
{
public void IncludeMappingOf<T1>()
where T2 : T1; // <== doesn't work
}
...
var mapping = MapManager.Find<Truck>();
// Truck inherits Vehicle
// Would like compiler safety here:
mapping.IncludeMappingOf<Vehicle>();
mapping.Serialize(new TonkaTruck());
Currently, I'm having to compare T1 and T2 at runtime using IsSubclassOf inside IncludeMappingOf. A compile-safe solution would be preferable. Any ideas?
EDIT:
Changed the example to be less design-smelly.
NOTE: The linked question is quite similar, but no suitable answer is given. Hopefully this question will shed some light on that one as well.
EDIT #2:
Simpler example:
public class Holder<T2>
{
public T2 Data { get; set; }
public void AddDataTo<T1>(ICollection<T1> coll)
//where T2 : T1 // <== doesn't work
{
coll.Add(Data); // error
}
}
...
var holder = new Holder<Truck> { Data = new TonkaTruck() };
var list = new List<Vehicle>();
holder.AddDataTo(list);
Compiler: Argument type 'T2' is not assignable to parameter type 'T1'. Yes I know that, I'm trying to get the compiler to allow only cases where T2 IS assignable to parameter type T1!
While w0lf's answer gives a direct solution, I want to give some background explanation.
When you write something like
class C<A> where A : B
or
void F<A>() where A : B
the constraints of the form A : B must have A as one of the generic type parameters on the class, interface, method, etc. being declared.
The error you are facing is not because you've placed a generic type parameter of the current declaration on the right side of the colon (that's legal) - it's because you've placed a generic type parameter of an outer declaration (not of the current declaration) on the left side of the colon.
If you want to form a constraint A : B on some declaration, A must be introduced on that declaration and the scope of A must be less than or equal to the scope of B. The reason this is a pragmatic language restriction is that, for any generic type parameter T, it isolates any reasoning about constraints on the type T to the single declaration where T is being introduced.
Declare both generic types and the generic constraint at class(interface) level:
public interface IMapping<T1, T2> where T2 : T1
{
void IncludeMapping(IMapping<T1, T2> otherMapping);
}
You can use extension methods to come close to what you want. Using your holder example it would be:
public class Holder<T2>
{
public T2 Data { get; set; }
}
public static class HolderExtensions
{
public static void AddDataTo<T2, T1>(this Holder<T2> holder, ICollection<T1> coll)
where T2 : T1
{
coll.Add(holder.Data);
}
}
That then allows your example calling code to compile without error:
var holder = new Holder<Truck> { Data = new TonkaTruck() };
var list = new List<Vehicle>();
holder.AddDataTo(list);
The mapping example is complicated by the fact that it is an interface. It may be necessary to add an implementation method to the interface if there is no way to implement the extension method from the existing interface. That means you will still need a runtime check, but callers can get the good syntax and compile time checking. That would be something like:
public interface IMapping<T2>
{
void IncludeMappingOf(Type type);
}
public static class MappingExtensions
{
public static void IncludeMappingOf<T2, T1>(this IMapping<T2> mapping)
where T2 : T1
{
mapping.IncludeMappingOf(typeof(T1));
}
}
Unfortunatly, the IncludeMappingOf does not have a parameter of type T1 so the type parameters cannot be inferred. You are forced to specify both types when calling it:
var mapping = MapManager.Find<Truck>();
mapping.IncludeMappingOf<Truck, Vehicle>();
mapping.Serialize(new TonkaTruck());
That can often be worked around by changing the API to include a parameter (i.e. truckMapping.IncludeMappingOf(vehicleMapping)), changing which method/class the parameter is on or in fluent APIs creating chains (i.e. mapping.Of<Vehicle>().Include()).

Why does this static factory method involving implied generic types, work?

Consider
public class Tuple<T1, T2>
{
public Tuple(T1 v1, T2 v2)
{
V1 = v1;
V2 = v2;
}
public T1 V1 { get; set; }
public T2 V2 { get; set; }
}
public static class Tuple
{
// MAGIC!!
public static Tuple<T1, T2> New<T1, T2>(T1 v1, T2 v2)
{
return new Tuple<T1, T2>(v1, v2);
}
}
Why does the part labeled "MAGIC" in the above work? It allows syntax like
Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2"), but ... how and why?
Why do I not need Tuple.New<int,string>(1, "2") ??
This is called generic type inference and it works for generic methods only. You can pass instances of whatever types you want as the arguments to New and the compiler infers that you mean to return the particular generic Tuple that matches the arguments like Tuple<int, string>...
This is "Type Inference". See a great article here for details.
What is magic about it? You have two types, one that accepts generic type parameters and one that does not. They share the same name but they are not the same type. Try renaming one of them and see if it makes a little more sense to you.
/Klaus
C# Compiler automatically infer type and compile your
Tuple.New(1, "2")
to
Tuple.New<int,string>(1, "2")

Categories

Resources