Description
I would like to create a generic method with a single generic type input that has the return type of the generic parameter of the supplied type input.
In the context of this problem, having an instance parameter is not an option as instances would not exist in the callers context.
Example
Given the following interface:
interface IFoo<T> { }
What I am trying to achieve is something along the lines of the following improper method declarations.
TInner GetFoo<T>() where T : IFoo<TInner>;
T GetFoo<IFoo<T>>();
Which would be used like so:
class FooA : IFoo<int> { }
int foo = GetFoo<FooA>();
Question
How would such a method be declared properly (if it is even possible)?
Thanks in advance!
As suggested in the comment by elgonzo, the most natural solution to your problem is a declaration of the form
TInner GetFoo<T, TInner>() where T : IFoo<TInner>
Although your idea of declaring it as TInner GetFoo<T>() where T : IFoo<TInner> is sensible, this is currently unsupported. It is akin to higher kinded parametric polymorphism a feature dearly awaited by functional programming enthusiasts.
Related
I'm making a RTS game with Unity. There're many types of resources in my game, such as, tree, farm. Each resource is a GameObject and has it own main script controlling it.
Ex. I want to harvest a tree, I call this.
gameObject.GetComponent<Tree>().Harvest();
If I want to harvest farm I call the same script but change "Tree" to "Farm" which is fine but code will be duplicated. So I abstract it by using generics method like this.
void Harvest<T>(){
gameObject.GetComponent<T>().Harvest();
}
But the C# compiler won't let me do that. I want to know is it possible to define generics method that use generics method inside? If not, Is there any way to abstract my code like this? Thank you.
Error message:
'T' does not contain a definition for 'Harvest' and no extension method 'Harvest' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?) [Assembly-CSharp]
The problem is that in ...
void Harvest<T>(){
gameObject.GetComponent<T>().Harvest();
}
... the C# compiler does not know of which concrete type T will be. Therefore, it cannot know that there will be a method Harvest available, nor does it know its exact declaration (does it return void or bool or something else? Does it have optional arguments?). Because C# is a strongly typed language, this must be known at compile time. This gives you the certainty that everything will go well at runtime.
The solution is to give the compiler a hint by specifying a generic type constraint. To do this you must declare an interface and let the components with a Harvest method implement it.
public interface IHarvestable
{
void Harvest();
}
Specify the constraint with:
void Harvest<T>() where T : IHarvestable
{
gameObject.GetComponent<T>().Harvest();
}
In other situations where you are in control of the base class, you can also declare the required methods in the base class (possibly as abstract) and specify the base class in the generic type constraint instead of an interface.
Define an interface for all objects that use Harvest(), then define that T extends that interface:
public interface IHarvestable
{
void Harvest();
}
// In your class:
void Harvest<T>() where T: IHarvestable
{
gameObject.GetComponent<T>().Harvest();
}
BAD alternative (mentioned just as a "hacky" addition to the answer because C# supports this - do NOT use it in practice): If you want to skip -time checking you can use dynamic:
dynamic harvestable = gameObject.GetComponent<T>();
harvestable.Harvest();
Note this is a bad practice, leading to method call resolving at runtime, leading to performance drawbacks and making your code much more error prone. For instance, usage of method from a T type instance which does not implement Harvest() will be allowed by the compiler, leading to a runtime error.
Today my brain went dead, and I couldn't figure out a clean way of forcing the compiler to use inheritance for Generic inference.
Imagine the following 4 classes
Models
public abstract class Model
{
}
public class CodePerfModel : Model
{
}
Entities
public abstract class ModelEntity<TModel> where TModel : Model
{
public TModel Model { get; set; }
}
public class CodePerfEntity : ModelEntity<CodePerfModel>
{
}
Now to me logically I should take for granted that when I take something that inherits from ModelEntity<> (it will specify the type of TModel) via inheritance, because any class that inherits from ModelEntity<> will have to specify it.
Is there anyway to force the compiler to figure this out for me?
E.g.
If I currently want to use ModelEntity<>, I have to specify a type for it. Such as the following:
public class CallerClass<TEntity, TModel>
where TEntity : ModelEntity<TModel>
where TModel : Model
{
}
How can I get rid of the TModel argument everywhere? While still having access to the TModel type at compile time? E.g. via the base Model property.
To me, something like the following:
public class CallerClass<TEntity>
where TEntity : ModelEntity<>
{
}
Would make perfect sense as when calling it all I should have to speicfy is e.g.
SomeCall<CodePerfEntity>();
rather than
SomeCall<CodePerfEntity, CodePerfModel>();
Is this something that is currently possible?
Would this be worth raising for C# 6/7?
You mention you would like to access TModel at compilation time, while not explicitly specifying this type when deriving a class. Letting go of your example, and moving to a more general case, this means you would like the semantics to remain the same, however you would not like to explicitly declare the type parameter's own type parameters when declaring a generic constraint.
In essence, you are asking why a specific syntax sugar feature is not implemented.
Let's consider another example:
public class CallerX<A, B> where A : ModelEntity<> where B : ModelEntity<>
From the example in your question, the compiler should insert TModel'1 and TModel'2 as type parameters for A and B respectively. Let's say the feature is implemented. This means that we have created the default situation that TModel'1 and TModel'2 are different types, each having constraints that match the single type.
What if I would like to add more constraints to either TModel'1 or TModel'2, or force them to be the same type? Why is this case so special that it deserves its own syntax?
From what I know of the C# team, they have the policy that each new feature starts with "-100 points" and should be really great in order to be considered (see UserVoice for C#).
To summarize:
New language features are expensive and add complexity.
You are asking for an implicit syntax for which it is unlikely/unclear that it will be the desired situation in most of the cases.
Developers will have to learn and understand that an open generic type as a type parameter constraint will insert a hidden and anonymous extra parameter. To me, it is not intuitive that some other type parameter has been added to my type without me having declared it.
I have a generic interface:
public interface IUnauthorizedRequestRespondable<out T> where T:class
{
T GetResponseForUnauthorizedRequest();
}
(I'm not sure why Resharper recommended T is "out", but that's not the question).
In my scenario, the object returned by GetResponseForUnauthorizedRequest is always of the type that implements the interface.
So all the interface's implementations look like:
public class SignInReturnedObject : IUnauthorizedRequestRespondable<SignInReturnedObject>
(class name and the type in brackets are always the same).
Which seems a bit awkward - isn't there a neater way to tell the compiler that the interface's method returns the type it's a part of?
Thanks.
As far as I know, there is no way to do that currently in C#.
A theoretical side-note: The feature that would allow you to do this is called self types but that's not available in C#. The idea of the feature is that you have a special type that refers to the actual type of this, so if you had a special type named self, you could probably write something like:
public interface IUnauthorizedRequestRespondable {
self GetResponseForUnauthorizedRequest();
}
...and the actual type used in place of self when you have a class SignInReturnedObject implementing the interface would be SignInReturnedObject, but unfortunatelly, that's not
available in C# :-)
If the only way you want to use that template is in that manner, I would use:
public interface IUnauthorizedRequestRespondable<T> where T:IUnauthorizedRequestRespondable<T>
{
T GetResponseForUnauthorizedRequest();
}
This has the advantage of guaranteeing it isn't used in any other way.
The class declaration won't change, but I don't see anything as awkward in this myself. Considering that you are defining a relationship between the class and itself, any more concise form might be inadvisable.
Actually, that about sums it up. That is how the syntax works.
You can see it used in .NET itself with the IEquatable inteface--you are almost always comparing an object to itself, yet you always have to provide your own class name as a template parameter.
This is simply to provide flexibility such that you can compare to anything, not necessarily yourself.
You can create a nongeneric version and just use that but I think it is more trouble than it is worth
public interface ICastUnauthorizedRequestRespondable : IUnauthorizedRequestRespondable<SignInReturnedObject>
{
}
Since T can be any class (does not have to be the class you are implementing) you need to name your class.
public class SignInReturnedObject : IUnauthorizedRequestRespondable<ANYCLASS>
I would like to implement a generic C# class which looks roughly as follows:
abstract class Foobar<T> : AbstractBase, T
{ ... }
This fails because C# will only allow types after the base class to be interfaces, so next I try this:
abstract class Foobar<T> : AbstractBase, T where T : interface
{ ... }
But then I find that C# does not allow this form of type constraint. Only where T : struct and where T : class are allowed.
How can I dictate that a type parameter must only be an interface type?
Basically, you can't.
You can make a contstraint to a specific interface, but not a general one for all interfaces. So you can constrain to IEnumerable for example, but not any interface.
What do you need this for anyway?
The real problem with that code is that you are inheriting from a type parameter.
Trying to compile
abstract class Foobar<T> : T { ... }
will still fail with: error CS0689: Cannot derive from 'T' because it is a type parameter.
I think that this would be perfectly reasonable at least in the case of abstract classes, and I wanted this feature too, but the c# compiler just wont let you do that.
I believe that you misunderstand the meaning of where T : struct and where T : class.
A generic type constraint like this means that T must be a value type or a reference type respectively.
However, the purpose of an interface is to define a contract, which is a totally different concept as compared to value type vs. reference type semantics.
Therefore a restriction like where T : interface would make no sense.
If you want to know more, I would suggest you to read the C# Programming Guide on type constraints:
Constraints on Type Parameters (C# Programming Guide)
You can't in simple words.
This fails because C# will only allow types after the base class to be interfaces
This constraint is due to the lack of multiple inheritance in C#. Multiple inheritance can be approximated by the use of interfaces because the overriding methods are explicit. The same way a class can only extend one other class, but can implement multiple interfaces. The trick here is that the implementing class MUST define the body for a method, so that the implementation is specific on which method is called.
Using a where to limit T can be applied to one class, or several interfaces. You can not limit the range to several classes.
I want to write a generic class that should be casted to itself with a different generic argument.
class Base {}
class Inherited : Base {}
class MyGeneric<T> {}
// WCF Service interface
void Foo(MyGeneric<Base> b);
// somewhere else
MyGeneric<Inherited> inherited;
Foo(inherited)
I know that this could be done in C# 4.0, but this doesn't help for now.
I could write a specialized class for each MyGeneric<T> constellation, and there write an implicit type converter or implement a certain interface. But I want to avoid this.
I could have an interface with no generic, but the whole sense of the generic in this case is to get compile time type safety on the method Foo. So this is not an option.
Because Foo is a Operation Contract, it could not be generic itself.
Any ideas how this problem could be solved in C# 3.0?
You want:
void Foo<T>(MyGeneric<T> b) where T : Base {}
I wrote this casting method
public MyGeneric<TTarget> Cast<TTarget, TSource>()
where TTarget : class
where TSource : TTarget, T
{
return new MyGeneric<TTarget>();
}
which could be called like this
MyGeneric<Inherited> inherited;
Foo(inherited.Cast<Base, Inherited>());
The ugly thing is that one has to provide the class that it already is. There is probably some improvement possible.
By the way, I couldn't manage to make it an extension method, to avoid the second generic argument.
the whole sense of the generic in this case is to get compile time type safety on the method Foo
The purpose of casting in this way (to a type that is not in the instance's ancestry), is to break type safety. Don't break type safety to save type safety.