When i need to pass a Generic Type I can use the Syntax
(Example : Ofcourse it is not a Generic Method)
public void Sample(T someValue)
{
......
}
What is the benefit of declaring Sample<T> ?
I mean
public void Sample<T> (T someValue)
{
......
}
Generic types and generic methods are very different things. It sounds like you have a generic type:
class SomeType<T> {
public void Sample(T someValue) {...}
}
and are discussing having a generic method inside it:
class SomeType<T> {
public void Sample<T>(T someValue) {...}
}
These are very different. In the first, inside Sample, then T means "the T that got passed to SomeType<T>". In the second, inside Sample, this is a separate and independent T - "the T that got passed to Sample<T>". In fact, calling it T (in this case) is a mistake. You could have, for example:
var obj = new SomeType<int>(); // here T for SomeType<T> is int
obj.Sample<decimal>(123.45M); // here T for Sample<T> is decimal
Note that there is no easy way (within Sample<T>) of saying "the T in SomeType<T>" - hence why you should rename the method's generic type parameter.
There are valid scenarios for this type of scenario (generic methods on generic types), for example (and note the new name):
class SomeType<T> {
public void Sample<TActual>(TActual someValue) where TActual : T, new() {...}
}
This allows us to do some very interesting things in terms of inheritance, etc - or you might want a generic method that has little or no relation to T. That is fine too.
For this to work:
public void Sample(T someValue)
{
......
}
The type T has to be declared in the system already. And the method will only accept the type T or its derivatives.
By declaring this:
public void Sample<T> (T someValue)
{
......
}
you say the method will accept any type that comes.
Consider the following:
class SomeClass<T>
{
public void Sample(T value)
{
// code goes here
}
}
or this:
class SomeClass
{
public void Sample<T>(T value)
{
// code goes here
}
}
In the first case, for all calls to Sample in a specific instance T will be the same type. In the second case each call in a specific instance can have its own type of T, since the generic type argument is supplied with the method call.
The second approach can have many uses, but one that I have used myself sometimes is in factory methods:
public static class SomeFactory
{
public static T CreateSomeObject<T>()
{
T result = Activator.CreateInstance<T>();
// perform any extra initialization
return result;
}
}
You can use the 2nd example if your class isn't generic. It means you can make just that method generic. If your class is generic, you should use your 1st example.
Related
This question already has answers here:
Calling a static method on a generic type parameter
(9 answers)
Closed 3 years ago.
Example:
Public class a<T> where T: containsStatic
{
public void func()
{
T.StaticMethod();
}
}
Is it possible? And if not is there another way to do it?
EDIT:
it gives me the error: "'T' is a type parameter, which is not valid in the current context."
why is that? is there a way to fix this?
The problem I forsee with this is how do you guarantee that T supports StaticMethod?
However if you are sure that StaticMethod will always exist on T, you can use reflection to accomplish this fairly simply:
using System.Reflection;
public void func()
{
var staticMethod = typeof(T).GetMethod("StaticMethod", BindingFlags.Public | BindingFlags.Static);
staticMethod.Invoke(null, null);
}
Assume we wave a magic wand and you can do that now. Assume a type C:
public class C
{
public static void Foo()
{
}
}
How would this:
public class A<T> where T : C
{
public void Func()
{
T.Foo();
}
}
Be any different from:
public class A<T> where T : C
{
public void Func()
{
C.Foo();
}
}
It would not. It would have to be the same method being called. A static method call is generated statically (yeah, I know) when the method's code gets generated. The compiler seeing T.Foo() wouldn't possibly be able to insert any other call than C.Foo() there.
So you can't even express that in C#'s grammar, a type parameter is disallowed by the spec in such a context:
A type parameter cannot be used in a member access (Member access) or type name (Namespace and type names) to identify a static member or a nested type.
If you want to dynamically call a static method depending on T's value at runtime, refer to #Martin 's reflection solution.
You can call any static method, if it does not depend on the Generic Type.
If you have a class like
public class Test<T>
{
public static int Result => 5;
}
You can call
int n = Test<int>.Result;
at any place you want, and it is not important what type you actually insert, since any type will do the same
int n = Test<string[]>.Result;
will do the very same thing.
If your function depends on T like in
public class Test1<T>
{
public static void Action(T param)
{
}
}
You can use
Test1<int>.Action(8);
At any place you want.
Also inside other generic classes:
public class OtherClass<T>
{
public void Method(T param)
{
Test1<T>.Action(param);
}
}
But most often it is possible to write a generic function in a non-generic class like
public class Test2
{
public static void Action<T>(T param)
{
}
}
This works at any place in the Program
Test2.Action("string");
Test2.Action(9);
You can put this function in any class you want, since it's static. There is no need to put this function in a generic class.
example
i have a class
using System;
namespace ConsoleApp1
{
public interface INode<T>
{
T Value { get; }
}
public class A
{
public void Do1(INode<string> node) { }
public void Do2<T>(INode<T> node) { }
}
public class Programm
{
public static void Main(string[] args)
{
A a = new A();
//now I want to pass this method to an another class as arguments
//it's OK here
var processor1 = new Proccessor(a.Do1);
//no idea how to achieve this without making class Proccessor generic type
var processor2 = new Proccessor(a.Do2);
}
}
public class Proccessor
{
//it's OK here
public Proccessor(Action<INode<string>> do1Action)
{
}
//no idea how to achieve this without making class Proccessor generic type
public Proccessor(Action<T><INode<T>> do2Action)
{
}
}
}
It looks like you're trying to pass an Action<T> to a method such that the method can then choose which T to invoke it for. That's simply not possible.
The easiest way around this is avoiding generics entirely, by making all BaseNodeViewModel<T, U> derive from a common non-generic BaseNodeViewModel type. Your OnNodeExpanded then looks like
private void OnNodeExpanded(BaseNodeViewModel node) { ... }
and it may cast node to the concrete type as needed in its implementation.
A more advanced way around this is creating a custom interface type
internal interface INodeExpanded {
void OnNodeExpanded<TNode>(BaseNodeViewModel<TNode, FolderTreeViewModel> node);
}
You can then manually create a class which implements this interface, and pass that to A instead of a delegate.
The answer to this question depends on what exactly you expect to be able to do with do2Action inside the class.
Do you to say "I want to accept and store an action that will be able to work with any INode"? Assuming that's the case, make INode covariant, and demand an Action<INode<object>>. Like so:
public interface INode<out T>
{
T Value { get; }
}
Then...
public Proccessor(Action<INode<object>> do2Action)
{
}
Now you can do:
var processor2 = new Proccessor((Action<INode<object>>)a.Do2(x));
The cast is required to disambiguate from the string overload, but if you remove the overloads and instead use distinctly named static methods to construct, you will find that this is type safe.
Note that an immense responsibility has now been pushed to a.Do2, it must be able to work with any INode whatsoever, without restriction.
You can't have a generic constructor for a non-generic class. You have at least 3 options (Asad's answer is also very good if your intentions are what he specified in his answer):
don't use generics. see hvd's answer.
make the class generic.
don't use T in the constructor, but in another method. You can have a static method that will create and return an instance of the class for you, there you can use the generic action:
public class Proccessor
{
//it's OK here
public Proccessor(Action<INode<string>> do1Action)
{
}
private Proccessor()
{
// a private constructor for the CreateProcessor static method
}
public static Proccessor CreateProccessor<T>(Action<INode<T>> do2Action)
{
var proccessor = new Proccessor();
// invoke action here
}
}
Here's the situation. I have a class and a derived class
public class MyClass
{ }
public class MyDerivedClass : MyClass
{ }
And also I have a method (in an external class) which takes an instance of MyClass as a parameter:
public class AnotherClass {
public void DoSomething(MyClass myClass)
{ }
}
How can I restrict DoSomething method to accept instances of MyClass only, but not instances of MyDerivedClass?
If that's what you want then you would need to check in code yourself that if it is a Derived type through Exception to tell the calling code that Derived type objects are not allowed for this method:
public class AnotherClass {
public void DoSomething(MyClass myClass)
{
if(myClass.GetType() != typeof(MyClass))
{
throw new Exception("Derived objects not allowed");
}
}
}
What are you trying to do here is more related to an Invariance problem that is pretty common on all programming languages.
Means that you can use only the type originally specified; so an
invariant generic type parameter is neither covariant nor
contravariant. You cannot assign an instance of IEnumerable
(IEnumerable) to a variable of type
IEnumerable or vice versa.
Here is the reference for you https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
My advice, try to change the implementation and put all the methods into an interface, that should be more clear
class Root: Interface
{
...implementation of your common methods
}
class Derived: Interface
{
...implementation of your common methods
//this should just
public void DoSomething(MyClass myClass)
}
If you don't want to use the above approach then use the "as" operator to treat the parameter that you are passing as MyRootClass, var a = parameter as MyRootClass. If a is null then you are not passing the correct value to the method, or check for the type directly.
If would recommend that you read this topics:
http://amapplease.blogspot.com/2009/04/invariance-covariance-contravariance.html
https://stackoverflow.com/a/13107168/819153
https://blogs.msdn.microsoft.com/ericlippert/2009/03/19/representation-and-identity/
Hope this helps
In the code below, I want to use an action having a more derived parameter pass into an action using the base as a parameter. The code looks like this:
public interface IContext<T>
{
}
public interface IWorkflow<T>
{
void Do(Action<IContext<T>> lambda);
}
public interface IDerivedContext : IContext<int>
{
}
public interface IDerivedWorkflow : IWorkflow<int>
{
void Do(Action<IDerivedContext> lambda);
}
public class Workflow<T> : IWorkflow<T>
{
public void Do(Action<IContext<T>> lambda)
{
Console.WriteLine("in Do(Action<IContext<T>>");
}
}
public class DerivedContext : IContext<int>
{
}
public class DerivedWorkflow : Workflow<int>, IDerivedWorkflow
{
public void Do(Action<IDerivedContext> lambda)
{
base.Do(lambda); // Compiler error:
}
}
If I cast this line:
base.Do(lambda);
like this:
base.Do((Action<IContext<int>>)lambda);
The compiler accepts the cast but code fails at runtime with an InvalidCastException.
Based on the MSDN documentation it suggests that the above should work because I'm passing an Action with a parameter of a more derive class to an Action using a parameter of a least derived class (in this case the base class) for example the docs illustrates the following:
static void AddToContacts(Person person)
{
// This method adds a Person object
// to a contact list.
}
static void Test()
{
// Create an instance of the delegate without using variance.
Action<Person> addPersonToContacts = AddToContacts;
// The Action delegate expects
// a method that has an Employee parameter,
// but you can assign it a method that has a Person parameter
// because Employee derives from Person.
Action<Employee> addEmployeeToContacts = AddToContacts;
}
}
Am I misunderstanding something or is there a workaround to this problem.
Thanks in advance
That's fundamentally unsafe; you can't do that.
An Action<IDerivedContext> can only take an IDerivedContext as a parameter. Had you been able to convert it to Action<IContext<int>>, you would be able to call it with some other IContext<int> implementation that it can't actually accept.
Let's say I have the class
class SomeClass<T>
{
public static void someMethod(T param1) // this gives an error
// I have to do something like (var param1)
{
// ...
// ...
}
}
How could require param1 to be of type T so that I can call the method as:
SomeOtherClass object1 = new SomeOtherClass();
SomeClass<SomeOtherClass>.someMethod(object1);
class SomeClass<T>
{
public static void someMethod<T>(T myobject)
{
}
}
Just use a generic method instead.
public static void SomeMethod<T>(T param1) ...
I do not know C# very well, but I think you would want to apply the generic type definition to the method rather than the class.
public static void someMethod<T>(T param1)
{
//not sure where <T> definition goes in signature...
}
What error do you get? It is probably related to something other than the method signature. This works fine for me:
class SomeClass<T>
{
public static void someMethod(T param1)
{
Console.WriteLine(param1);
}
}
...
SomeClass<int>.someMethod(4);
Tono your code is right. According to what Brandon says (and dislike some other pretend), you don't have to make your method generic since the whole class it belongs to is already generic... except if you'd wish to have a type parameter for this method different from the class' type parameter :
class SomeClass<T>
{
public static void someMethod<U>(U myobject)
{
}
}
Which, obviously, is absolutely not what you want.
By the way in danyolgiax' answer, the compiler will raise an error because of the conflict name between the class' type parameter named T and the method's type parameter also (badly) named T.
It is sure your error comes from somewhere else. Why not mentioning the exact error message you get ? This will be half way to the solution. :-)