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.
Related
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.
I have no experience in objective c and am trying to translate a class written in objective c to c#. In the objective C class there is the "__kindof" keyword, such as
- (NSArray<__kindof NSViewController *> *)popToViewController:(__kindof NSViewController *)viewController animated:(BOOL)animated;
I researched about this keyword, and the documentation says that it allows NSViewController's subclass to be passed as parameter or element in the array. So I am wondering if there is a similar thing in C#. If not, are we allowed to just pass subclass of NSViewController as this method's parameter or the NSArray's element?
You are mostly talking about Inheritance by means of inheriting a abstract base class or implementing a Interface. Then you can pass in a sub-class instance in place of base-class.
Something like below:
public interface INSViewController { ... }
public class ChildNSViewController : INSViewController {... }
//Your method definition
public IEnumerable<INSViewController> popToViewController(INSViewController arg) {... }
You can call this method now with child type as parameter
popToViewController(new ChildNSViewController())
So I am wondering if there is a similar thing in C#.
Not as such. Effectively __kindof allows a cast which might fail to be omitted - hopefully because the code has done a test and knows it won't.
For example: if Y is a subclass of X and you have a variable of type X then you can test if it is a Y, cast to Y, and call a Y method. If the variable has type __kindof X then the cast step can be omitted. Objective-C however does not statically enforce the test step, relying on runtime tests to catch any error.
C# 7's pattern matching feature can be used to do something sort-of similar, in that you can test (in an if or switch) if something is of a particular type and bind a name to it as that type - so again avoid casts after the test. Unlike the Objective-C feature the test part is required.
If not, are we allowed to just pass subclass of NSViewController as this method's parameter or the NSArray's element?
Yes. In your C# code you might require casts/is/as uses that are implicit in Objective-C - unless you favour dynamic and run time tests.
HTH
I have a method with a generic parameter:
internal void DoSomething<T>(T workWithThis)
{
}
I now want to constrain this method to only accept parameters which inherit one of a few interfaces I'd like to specify. However I have not yet found a way to it. What I'd like looks like this:
internal void DoSomething<T>(T workWithThis) where T : ISomething | ISomethingElse
{
}
Obviously this is not working, so I tried it with a static method to check the Type of T:
public static bool CheckType(Type t)
{
return */check here*/
}
internal void DoSomething<T>(T workWithThis) where T : CheckType(typeof(T))
{
}
Obviously this is not going to work either. The question is why? Why is the compiler preventing me from doing that, based on my understanding there is no reason for it not to work
Why is the compiler preventing me from doing that, based on my understanding there is no reason for it not to work
The compiler is preventing you from doing it because you're trying to do something which isn't supported by C# as a language. The syntax you're trying to use does not comply with the productions in section 10.1.5 of the C# spec.
C# as a language simply does not support the scenario you require.
Now as for why the language doesn't allow this sort of flexibility - that comes down to the normal balancing act of:
How many developers would benefit from this and how much
Extra burden on other developers to understand a more complicated language
Resources (primarily within Microsoft) required to design the language feature, implement and test it
Oh, and of course this isn't just C# - the CLR would have to support such a restriction as well, and it would at least encourage other CLR languages to understand it too.
I suggest you solve this by having two separate methods. Note that they can't just be overloads of generic methods, as overloads cannot differ only by generic type constraints. If you don't mind about boxing for value types implementing the interface, you could overload with:
internal void DoSomething(ISomething something)
{
}
internal void DoSomething(ISomethingElse somethingElse)
{
}
... although then if you pass in a value where the expression is a type implementing both interfaces, you'll end up with overload ambiguity.
Alternatively, just give the two methods different names.
The compiler has to verify all the constraints at compile time, and cannot call a method to do so.
The only things you can specify in the where constraints are:
new() - require a parameterless constructor
class - must be a reference type
struct - must be a value type
SomeBaseClass
ISomeInterface
T : U - must be, inherit from, or implement one of the other generic parameters
See the C# Programming Guide - Constraints on Type Parameters for more information.
As for why, you should never have to answer "I see no reason for this to work". You have to start in the opposite direction, "Why should this work", and then come up with enough plausible and realistic scenarios and requirements to make it worthwhile to implement. See Minus 100 Points by Eric Gunnerson.
To fix this in your code, you should derive both interfaces from a common interface, and add a constraint on that instead.
If the two interfaces have nothing in common, then I question the benefit of actually adding a constraint in the first place.
For instance, if your code is going to call a method on the objects being used with the generic type/method, then obviously both interfaces have to have the same notion about what that method is, and the only way to do that would be for the method to be defined in a common base interface. That the two interfaces happen to have the same method or property declared, with the same signature, does not make it the same method.
Having said that, are you sure you even need generics here?
How about just declaring two methods, each taking one such interface?
internal void DoSomething(ISomething workWithThis)
internal void DoSomething(ISomethingElse workWithThis)
The compiler uses the generic constraint to determine what operations is available on T within the generic method - so allowing an or expression would not be type safe. For example you have two interfaces IFirst and ISecond:
public interface IFirst
{
void First();
}
public interface ISecond
{
void Second();
}
internal void DoSomething<T>(T workWithThis) where T : IFirst or ISecond
{
//How to call this method if the type is ISecond
workWithThis.First();
//How to call this method if the type is IFirst
workWithThis.Second();
}
You can define an empty interface that holds all of them.
Remember, that in C# interfaces can have multiple inheritance.
For example:
public interface IHolder : ISomething, ISomethingElse
{
}
and for generic
internal void DoSomething<T>(T workWithThis) where T : IHolder
{
}
I am using silverlight 4.0 in my application. I have a method in my base class as mentioned below
class BaseClass
{
protected CustomRequest GetCustomRequest(IEnumerable<IRequestType> types)
{
//Some code here...
}
}
In my derived class when I call this method like below I get error
IEnumerable<RequestType> requestTypes = CodeToGetThis();
GetCustomRequest(requestTypes)
Note here that in calling statement the type of requestTypes is a enumerable of derived type of IRequestType.
This works well in desktop applications due to introduction of covariance in c#4.0. But it seems that for silverlight 4.0 it is not done for IEnumerable interface.
So what is the best alternative approach I should use in my silverlight application for this?
I somewhere read that it can be done using method overloading but not sure how to do this.
UPDATE:
One thing I missed in the first draft of the question is, I will have many derived types of IRequestType hence craeating overloaded method for each derived type will be a difficulty for me.
Just cast each item to the interface e.g.
IEnumerable<IRequestType> requestTypes = CodeToGetThis().Select(x => (IRequestType)x);
GetCustomRequest(requestTypes)
You could do something with method overloading and have a method that took your derived/concrete type but you would only end up doing something like the above and calling the original method in the overload.
It is valid (ie. it compiles and runs) to put an attribute on the generic parameter for a class or a method:
public class MyClass<[My] T>
{
private void MyMethod<[My] T>()
{}
}
public class MyAttribute : Attribute
{}
I've never seen this used, and am struggling to come up with a reason as to why you would want to.
Is it just a quirk/side-effect of the language specification, or is there a valid/useful reason to put an attribute in this position?
For the same reason attributes are useful on any construct; they supply meta-data that can be used by Reflection or other post-processors to do various things. For instance, you might have an AOP system that uses an attribute on a type argument to apply certain run-time constraints that otherwise could not be expressed. I'm not sure if there are any systems that actually use these attributes to do anything, but there's no reason to disallow them as metadata.
I'm sure some AOP nut will find a valid reason to decorate generic parameters with attributes. I certainly can't think of any. Try this:
typeof(MyClass<>).GetGenericArguments().GetCustomAttributes().OfType<MyAttribute>();
If this Enumerable has any elements, then it is possible to access the attribute you placed on the class's generic parameter. If not, then you can't and thus having data you'd expect to access from any other class in your codebase is pointless. HOWEVER, they can still have code that runs when instantiated, and they're instantiated by the runtime when the generic class comes into scope, allowing you to perform aspect-oriented logic in the attribute itself. Exactly what that would be, and how it would be any different than decorating the generic class or method directly, is left as an exercise to people who worship AOP far more than I do.