I have a class that takes a generic as a parameter like this
public MyNewClass(string text, T myClass, int f, bool test = false)
The compiler is complaining about T myClass.
I know I can pass "defined" generic classes to a class constructor (such as List, Dictionary etc) and have seen that this can be done in C# as well, but can't find a reference to it.
You should declare the generic parameter, when you declare your class.
public class MyNewClass<T>
{
}
Then this parameter could be accessible from any of the class's methods. When you will create an instance of your MyNewClass, you should define also the type of T, for instance:
var instanceOfMyNewClass = new MyNewClass<className>(text, classIntance, f, true);
where classInstance is an instance of an object of type className.
A good introduction about generics is here.
I suspect that the issue you are facing is that the following does not compile
public class Foo<T>
{
public Foo(string s, T t) { }
}
var foo = new Foo("Hello", new Something());
The fix to this is to specify in the constructor.
var foo = new Foo<Something>("Hello", new Something());
However, this still seems a little strange given that normally, the C# compiler can infer the type of T.
The problem here is that the C# compiler is only allowed to infer generics on the first parameter of a method. So the following IS allowed.
public class Foo<T>
{
public Foo(T t, string s) { }
}
var foo = new Foo(new Something(), "Hello");
Related
I'd like to instantiate instances of a generic type and pass them around as if they were generic objects of an interface that they implement, such as below. Clearly, this is not allowed. Why is this, and what is the general practice for handling such situations? thanks.
public class MyType<T> where T : IComparable { }
MyType<IComparable> things = new MyType<Int32>();
this gets error:
Cannot implicitly convert type MyType<Int32> to MyType<IComparable>
I want to do this because I need different types of things that I want to pass around to more generic methods such as
public void DoSomething(MyType<IComparable> things) {...}
The assignment compatibility of generic type arguments does not make the generic type itself assignment compatible. This is why: Let's assume that we declared the generic class like this:
public class MyType<T> where T : IComparable
{
public T Value { get; set; }
}
And let's assume that this would compile ...
var intObject = new MyType<int> { Value = 42 };
MyType<IComparable> things = intObject; // Does not compile!
... then we could write
// things.Value has the static type IComparable
things.Value = "hello"; // Allowed because string is IComparable
But this is not possible since the underlying object is a MyType<int> and thus its Value property has the type int. Therefore, we are not allowed to substitute a MyType<int> for a MyType<IComparable>.
One thing that irritates me about Java is the awful implementation of compile-time translation of generic type arguments.
I can observe and understand that the C# implementation is far better, but I'm confused as to how it works.
Essentially, how can you say:
T t = new T()
If you don't know the type of T and therefore don't know the constructor argument requirements?
I can see
Class<T> cl = T.class
or
T[] tarr = new T[0]
but I don't see how you can really create a new instance of T if you don't know the requirements of constructing it?
You can only do new T(); if T is constrained to have a plain, parameterless public constructor, for instance:
public class Foo<T> where T : new() {
private myT = new T();
}
Additionally, there is no way to specify that any other sort of constructor exist. This is not possible:
// Doesn't work
public class Foo<T> where T : new(String, Int) {
private myT = new T("Foo", 5);
}
To your other points, this is how you get the type of T at runtime:
var tType = typeof(T);
and creating an array of T doesn't actually create any instances (unless T is a value type, in which case it creates the default value of that type):
// Space for 32 T's, but nothing in the array.
// If T is a value type, like an int for instance,
// each one would have the default value (0 for int, for example)
var arrayOfT = new T[32];
You cannot say new T() unless you constrain your generic type to have a parameterless constructor using the where T : new() constraint — see Constraints on Type Parameters.
And there are no “constructor argument requirements”, since the only supported constructor is the parameterless one. You cannot use, say, new T(false) — constraints of the form where T : new(bool) are not allowed.
Actually you ask the compiler to force T to have a parameterless constructor so he knows you can new T(). For example:
class Test<T>
{
T Create()
{
return new T();
}
}
It won't compile because the compiler can't be sure that T won't be an abstract class and that it'll have a default constructor. To make it works you have to add a constrain on the real type of T:
class Test<T> where T : new()
Now the compiler will force T to be a non abstract class with a default constructor. For example this code is not valid because the given type is abstract:
abstract class AnotherTest
{
public void Test()
{
Test<Derived> test = new Test<Derived>();
}
}
Again, if you try to use a class without default constructor the compiler will emit an error:
class AnotherTest
{
public AnotherTest(string someParameter)
{
}
public void Test()
{
Test<Derived> test = new Test<Derived>();
}
}
With an array it's a little bit different. Actually you simply ask the compiler to reserve the memory for a given number of slots, you do not allocate the memory for that objects (in case of reference types it'll simply put null in each slot).
References on MSDN
Introduction to generics
Generic type constrain
The new constrain
new T() is just a syntactical sugar for Activator.CreateInstance<T>()
I am wondering if it is possible to use the type of one variable to set as the type of another generic variable?
For example, say I have this code:
public class Foo: IBar<ushort>
{
public FooBar()
{
Value = 0;
}
public ushort Value { get; private set; }
}
I also have this class:
public class FooDTO<TType> : IBar<TType>
{
public TType Value { get; private set; }
}
In these examples, in the interface for IBar has the property
TType Value;
Then in my code I have this
var myFoo = new Foo();
var fooDataType = myFoo.Value.GetType();
//I know this line of code does not compile, but this is what I am looking to be able to do
var myFooDTO= new FooDTO<fooDataType>();
Is what I am looking for possible? Would it be too slow for high use code (because of using reflection.
You can do this via Reflection, by using Type.MakeGenericType.
This will have some overhead due to reflection, so you'd need to profile it to see if that will be an issue for you.
Why not use Method type inference:
public class FooDTO<TType> {
public TType Value { get; private set; }
}
public class Foo : FooDTO<ushort> { }
static FooDTO<T> GetTypedFoo<T>(T Obj) {
return new FooDTO<T>();
}
static void Main(string[] args) {
Foo F = new Foo();
var fooDTO = GetTypedFoo(F.Value);
}
Always when I read "generic" and "runtime" in one sentence, I always thing "bad design" or "doesnt understant what generic means". Possibly both.
Generic parameter is integral part of the type. So saying "Generate Generic Type At Runtime" is same as "Generate Foo class at runtime". You are either looking for reflection or change design of your algorithm.
Also var keyword is not going to help you in this case. Forget about it.
You're looking for compile-time reflection, a feature that C# doesn't have. So if you're looking for performance optimizations, the solutions are worse than the problem.
D does have this feature, though; you can easily write
int x = 0;
typeof(x) y = x + 2;
or even much more complicated expressions in D, and it's all evaluated at compile-time.
The core of what you want is:
var type = typeof(FooDTO<>).MakeGenericType(fooDataType);
object obj = Activator.CreateInstance(type);
however, you'll notice that this is reflection, and pretty much ties you to object. The usual workaround to this is to have access to a non-generic version of the API, so that you can work with object - for example (with the addition of a non-generic IBar):
IBar bar = (IBar)Activator.CreateInstance(type);
You can of course move the runtime/generics hit higher up - perhaps into a generic method; then everything in the generic method can use T, and you can use MakeGenericMethod to execute that method in the context of a particular T known only at runtime.
sTypeName = ... //do some string stuff here to get the name of the type
/*
The Assembly.CreateInstance function returns a type
of System.object. I want to type cast it to
the type whose name is sTypeName.
assembly.CreateInstance(sTypeName)
So, in effect I want to do something like:
*/
assembly.CreateInstance(sTypeName) as Type.GetType(sTypeName);
How do I do that? And, what do I take on the left side of the assignment expression, assuming this is C# 2.0. I don't have the var keyword.
Usually you let all classes, you want to instantiate this dynamically, implement a common interface, lets say IMyInterface. You can create an instance from the classname string like this:
Assembly asm = Assembly.GetExecutingAssembly();
string classname = "MyNamespace.MyClass";
Type classtype = asm.GetType(classname);
// Constructor without parameters
IMyInterface instance = (IMyInterface)Activator.CreateInstance(classtype);
// With parameters (eg. first: string, second: int):
IMyInterface instance = (IMyInterface)Activator.CreateInstance(classtype,
new object[]{
(object)"param1",
(object)5
});
Even if you dont have a common interface, but know the name of the method (as string) you can invoke your methods like this (very similar for properties, event and so on):
object instance = Activator.CreateInstance(classtype);
int result = (int)classtype.GetMethod("TwoTimes").Invoke(instance,
new object[] { 15 });
// result = 30
The example class:
namespace MyNamespace
{
public class MyClass
{
public MyClass(string s, int i) { }
public int TwoTimes(int i)
{
return i * 2;
}
}
}
Unfortunately there's no way in .NET to do what you want.
Possible partial solutions are:
If you know the type at compile-time (unlikely, since you're creating it at run-time from a string) then simply cast to that type:
YourType t = (YourType)Activator.CreateInstance(sTypeName);
If you know that all the possible types will implement a specific, common interface then you can cast to that interface instead:
IYourInterface i = (IYourInterface)Activator.CreateInstance(sTypeName);
If you can't do either of the above then, unfortunately, you're stuck with object and reflection.
.
Define a generic method in your class, and then you can cast like this:
public T Cast<T>(object obj)
{
return (T) obj;
}
string sTypename = "SomeClassName";
MethodInfo cast = this.GetType().GetMethod("Cast");
MethodInfo genericCast = cast.MakeGenericMethod(new Type[] { Type.GetType(sTypename) });
Object castedValue = genericCast.Invoke(this, new object[] { instanceToBeCasted });
But then I think, what is the point of such casting if you cannot store the casted value in a variable of the actual type, precisely because you don't know the actual type at the time of writing the code?
Is there a rule for knowing when one has to pass the generic type parameters in the client code when calling an extension method?
So for example in the Program class why can I (a) not pass type parameters for top.AddNode(node), but where as later for the (b) top.AddRelationship line I have to pass them?
class Program
{
static void Main(string[] args)
{
// Create Graph
var top = new TopologyImp<string>();
// Add Node
var node = new StringNode();
node.Name = "asdf";
var node2 = new StringNode();
node2.Name = "test child";
top.AddNode(node);
top.AddNode(node2);
top.AddRelationship<string, RelationshipsImp>(node,node2); // *** HERE ***
}
}
public static class TopologyExtns
{
public static void AddNode<T>(this ITopology<T> topIf, INode<T> node)
{
topIf.Nodes.Add(node.Key, node);
}
public static INode<T> FindNode<T>(this ITopology<T> topIf, T searchKey)
{
return topIf.Nodes[searchKey];
}
public static void AddRelationship<T,R>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
where R : IRelationship<T>, new()
{
var rel = new R();
rel.Child = childNode;
rel.Parent = parentNode;
}
}
public class TopologyImp<T> : ITopology<T>
{
public Dictionary<T, INode<T>> Nodes { get; set; }
public TopologyImp()
{
Nodes = new Dictionary<T, INode<T>>();
}
}
With respect to the second example, the compiler does not know what type you want for R; it only knows that it must implement IRelationship<T> and have a public default constructor. It can't infer it from any of the parameters you pass to the method because they are of type T. In that case, you need to tell it what class you want to be used for R. If you were to pass in, instead of create an instance of R, as an argument, it would be able to infer the type and you wouldn't need to supply them.
In the first case, you don't need to supply the types because the arguments are of the type and thus the compiler can infer the types that you mean.
Generally, you don't have to explicitly specify the type. You need it when the type is in fact an argument - and example to this is the linq function .Cast - it's type tells it what to do: Cast<Employee>()
In your case this is quite simple: AddRelationship<T,R> has three argumenta, all of type T - how can R be inferred?
I haven't done this particular setup, but my understanding of type inference is that the caller would not need to specify the type. this ITopology<T> topIf will refer to an instance in which the type is already declared. The extension method should pick up the same type parameter implicitly.
A lot of the LINQ extension methods are based on generic extension methods of IEnumerable. It's the same pattern that you're using. That's a good place to start looking.
And as always, test.
I think it is because you do not include any argument with type R in the function.