Using a Type Variable in a Generic

Initializing a Generic variable from a C# Type Variable

What you mean by this part is possible:

new AnimalContext<a.GetType()>();

Obviously that exact syntax is wrong, and we'll get to that, but it is possible to construct an instance of a generic type at runtime when you don't know the type parameters until runtime.

What you mean by this part is not:

AnimalContext<a.GetType()> a_Context

That is, it is impossible to type a variable as a generic type if you don't know the type parameters at compile-time. Generics are compile-time constructs, and rely on having the type information available at compile-time. Given this, you lose all the benefits of generics if you don't know the types at compile-time.

Now, to construct an instance of a generic type at runtime when you don't know the type until runtime, you can say:

var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);

Note that the compile-time type of a_context is object. You will have to cast a_context to a type or interface that defines the methods you need to access. Often what you'll see people do here is have the generic type AnimalContext<T> implement some interface (say IAnimalContext) or inherit from a non-generic base class (say AnimalContext) that defines the methods they need (so then you can cast a_context to the interface or the non-generic base class). Another alternative is to use dynamic. But again, keep in mind, you have none of the benefits of generic types in doing this.

Generics in C#, using type of a variable as parameter

The point about generics is to give compile-time type safety - which means that types need to be known at compile-time.

You can call generic methods with types only known at execution time, but you have to use reflection:

// For non-public methods, you'll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
.MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });

Ick.

Can you make your calling method generic instead, and pass in your type parameter as the type argument, pushing the decision one level higher up the stack?

If you could give us more information about what you're doing, that would help. Sometimes you may need to use reflection as above, but if you pick the right point to do it, you can make sure you only need to do it once, and let everything below that point use the type parameter in a normal way.

C#, instantiating a generic type - with variable type argument?

You just can't use C# generics the way you're trying to do in your snippet.

In order to use [C#] generics, the actual object type must be known at compile time.

You're trying to dynamically pass the object type as a type parameter. This is simply not possible.

Edit

Yes, it is possible to dynamically create generic objects using reflection. After all, generics is implemented both as a compile-time C# construct and as a .NET framework feature (as opposed to, say, Java, where it is only a compile-time feature based on Type Erasure). So, in .NET, through reflection, it is possible to implement the latter "bypassing" the former (which, again, would be impossible in Java).

But the OP clearly does not need that.

After all, entries is a List<IEntry>. IOW, the entries container does not "know" the concrete type of its elements (since it is bound to an interface). So, if each element to be add already implements IEntry, then this would be enough:

void Foo(params IEntry[] objects)
{
var entries = new List<IEntry>();
foreach(var o in objects)
{
entries.Add(o);
}

...
}

OTOH, if those objects do not implement IEntry, then the OP just need a pure, ordinary, old-school list of untyped objects:

void Foo(params object[] objects)
{
var entries = new List<object>();
foreach(var o in objects)
{
entries.Add(o);
}

...
}

So using reflection in order to dynamically create a generic container, even if possible, seems to be overkill for this particular use case.

Using a Type Variable in a Generic

Swift's static typing means the type of a variable must be known at compile time.

In the context of a generic function func foo<T>() { ... }, T looks like a variable, but its type is actually known at compile time based on where the function is called from. The behavior of Array<T>() depends on T, but this information is known at compile time.

When using protocols, Swift employs dynamic dispatch, so you can write Array<MyProtocol>(), and the array simply stores references to things which implement MyProtocol — so when you get something out of the array, you have access to all functions/variables/typealiases required by MyProtocol.

But if t is actually a variable of kind Any.Type, Array<t>() is meaningless since its type is actually not known at compile time. (Since Array is a generic struct, the compiler needs know which type to use as the generic parameter, but this is not possible.)

I would recommend watching some videos from WWDC this year:

  • Protocol-Oriented Programming in Swift
  • Building Better Apps with Value Types in Swift

I found this slide particularly helpful for understanding protocols and dynamic dispatch:

Sample Image

Calling generic method with Type variable

Lets assume that Foo is declared in class Test such as

public class Test
{
public void Foo<T>() { ... }

}

You need to first instantiate the method for type bar using MakeGenericMethod. And then invoke it using reflection.

var mi = typeof(Test).GetMethod("Foo");
var fooRef = mi.MakeGenericMethod(bar);
fooRef.Invoke(new Test(), null);

How can I cast a variable to generic type in Dart?

Dart does not provide a way to go from an object of type X to a type variable bound to X. There are good technical reasons for not allowing that (it allows the web compilers to know at compile-time which types can ever be bound to a type variable, which allows it to reduce the compiled code).

The dispose method is treating the type argument as its only argument and acting on the value of that type argument.
It makes me think you're trying to do something that the language is not designed for.

You're passing in a type argument, and then the code inspects that type of argument and behaves differently depending on the value. That's not what's usually meant by being "generic" - to act the in the same (generic) way independently of the types, so the only real effect of passing a type is to make the return type match the argument type.
(That's why Java can erase type arguments at run-time).

So, if you need to know a type for some object, either that object must provide it for you, or you have to store it from earlier (perhaps when the object was created).

So, if you really need to access the type argument that the cubit is implementing Cubit<X> of, the Cubit class needs to make it available to you. That will usually be with a method with a callback (like a visitor), something like:

abstract class Cubit<T> ... {
...
R visit<R>(R Function<C extends Cubit<T>, T>(C value) action);
}

class SomeCubit<T> extends Cubit<T> {
...
R visit<R>(R Function<C extends Cubit<T>, T>(C value) action) =>
action<SomeCubit<T>, T>(this);
}

If something like that's available, then you can do what you want as:

bloc.visit(<C extends Cubit<T>, T>(_) => BlocManager.instance.dispose<C>());

If something like that is not available, then you are in trouble.

You can detect a number of known types, with a bunch of if statements, but that's unlikely to be sufficient.

That means you need to remember the type from earlier, but since it looks like you just get a List<Cubit<Object>> that has already been created, that doesn't seem practical either.

If the BlocManager is your own class, consider changing it to use Type objects instead of type arguments (which is contrary to everything I usually say you should do), because then you can call ..dispose(bloc.runtimeType). I'd prefer to avoid that, but if other constraints make what you do impossible, then it might be the lesser evil.



Related Topics



Leave a reply



Submit