Dart - Casting List<SuperType> to List<SubType> using generics - sqlite

I am new to Flutter and Dart, coming from native Android.
Android has a very nice database abstraction architecture called the Room Persistence Library. As far as I am aware, no such database abstraction architecture exists for Flutter using the MVVM / MVC design patterns.
My solution was to create a Dart version of it myself. I got it pretty much done after a few headaches, but I cannot seem to get LiveData to work properly using generics.
I set up my class like this:
class LiveData<T> {
...
}
Now when I want to return some data, it can either be an Object or List<Object>. I found a neat hack for differentiating the two from T:
...
// Parse response
// This checks if the type is an instance of a single entity or a list.
if (entity is T) {
cachedData = rawData.isEmpty ? null : entity.fromMap(rawData.first) as T;
} else {
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
}
...
The problem lies in the second block:
cachedData = rawData.map((e) => entity.fromMap(e)).toList() as T;
With the error:
- Unhandled Exception: type 'List<Entity>' is not a subtype of type 'List<Vehicle>' in type cast
The question then becomes: How can I cast Entity to Vehicle when I do not have access to the Vehicle class. Only an instance of it is assigned to an Entity entity variable.
Here's a snippet to demonstrate my access to Vehicle:
final Entity entity;
...assign Vehicle instance to entity...
print(entity is Vehicle) // True
I've tried using .runtimeType to no avail. I have also thought about splitting LiveData into two classes, the second one being LiveDataList. Although this seems to be the easiest solution to not bug the code- it would bug me (bad pun is intentional) and break the otherwise pretty direct port of Room.
As a temporary solution, I have abstracted out the build logic into a generic function to be passed to the LiveData in the constructor.
final T Function(List<Map<String, dynamic>> rawData) builder;
And now I call that instead of the previous code to build the cachedData.
// Parse response
cachedData = builder(rawData);
With the constructor for the LiveData<List<Vehicle>> called when accessing all vehicles in the Dao<Vehicle> being:
class VehicleDao implements Dao<Vehicle> {
...
static LiveData<List<Vehicle>> get() {
return LiveData<List<Vehicle>>(
...
(rawData) => rawData.map((e) => Vehicle.fromMap(e)).toList(),
...
);
}
}

In Dart (and indeed in many languages) generics screws with the concept of inheritance. You would think that if Bar inherits from Foo, that List<Bar> would also be castable to List<Foo>.
This is not actually going to be the case because of how generics work. When you have a generic class, every time you use that class with a different type, that type is treated as a completely separate class. This is because when the compiler compiles those types, class MyGenericType<Foo> extends BaseClass and class MyGenericType<Bar> extends BaseClass are basically converted to something like class MyGenericType_Foo extends BaseClass and class MyGenericType_Bar extends BaseClass.
Do you see the problem? MyGenericType_Foo and MyGenericType_Bar are not descendants of one another. They are siblings of each other, both extending from BaseClass. This is why when you try to convert a List<Entity> to List<Vehicle>, the cast doesn't work because they are sibling types, not a supertype and subtype.
With all this being said, while you cannot directly cast one generic type to another based on the relationship of the generic type parameter, in the case of List there is a way to convert one List type to another: the cast method.
List<Entity> entityList = <Entity>[...];
List<Vehicle> vehicleList = entityList.cast<Vehicle>(); // This cast will work
One thing to note though, if you are casting from a supertype generic to a sub-type generic and not all the elements of the list are that new type, this cast will throw an error.

Related

ActivatorUtilities.CreateInstance giving "A suitable constructor not found" for simple examples

So I am building a complex case here with inheritance and IOC, need to use ActivatorUtilities to inject instances and pass parameters... no matter what I do I get the following error:
System.InvalidOperationException: 'A suitable constructor for type
'blabla.ISimpleTest' could not
be located. Ensure the type is concrete and all parameters of a public
constructor are either registered as services or passed as arguments.
Also ensure no extraneous arguments are provided.'
So in order to discard what could be the problem and ensure there is no constructor issues, I created a very very simple scenario that gives me the same error.
startup.cs
services.AddScoped<ISimpleTest, SimpleTest>();
the class and the interface, very simple here:
public interface ISimpleTest
{
}
public class SimpleTest : ISimpleTest
{
public SimpleTest()
{
}
}
test
var theInstance = ActivatorUtilities.CreateInstance<ISimpleTest>(ServiceProvider);
Additional notes
The ServiceProvider instance is fine (the rest/entire application depends on it).
Tried with and without adding the public constructor(empty params)
Tried also constructor with params, same error.
Tried to specify the params[] parameter, by sending null or empty array, same issue.
Extra test:
Just to confirm it's properly registered, I tried to get the instance using the Service provider, and works without issues:
//No issues this way:
var yyy = ServiceProvider.GetService<ISimpleTest>();
What am I doing here wrong? According to documentations, this should be enough to work

netcore DI container returns different instances for same registration with overloads

I encountered a Problem with the DI framework of netcore. I am aware about the different ways to register an type in the DI container.
Specifically I am interested in the .AddSingleton method. There are many overlaods of this method.
My Problem is that I want to ensure that when I register the same class in different ways (with an interface and just with the class type), then two instances are created, one for each "registration" way.
Lets say I have an Interface called ISomeInterface an one implementation of it named ImplementationOfSomeInterface.
In my case I want the DI system to create an instance whenever the ImplementationOfSomeInterface is requested. Further I have some places where I define the dependency just with the interface ISomeInterface.
The Problem is that the DI system returns 2 instances of ImplementationOfSomeInterface. One for the case where the dependency is related of the class and one for the case where the dependency is given by the Interface.
I already checked many documentation and tutorials, but they all just explain the differences of AddSingleton, AddScoped etc...
// registration with the class type
services.AddSingleton<ImplementationOfSomeInterface>()
//registration with an interface and the corresponding 'same' class type
services.AddSingleton<ISomeInterface, ImplementationOfSomeInterface>();
//--------- now the usage of it -------------------
public TestClassA(SomeInterfaceImplementation instance)
{
var resultingInstA = instance;
}
public TestClassB(ISomeInterface instance)
{
var resultingInstB = instance;
}
//I would expect that resultingInstA is pointing to the very same object of
//resultingInstB => but they are different!
I would expect that resultingInstA is pointing to the very same object of resultingInstB => but they are different!
How can I achieve that I get the same instance back?
You can do it by registering an instance of the class rather than just the type.
var instance = new ImplementationOfSomeInterface();
services.AddSingleton(instance);
services.AddSingleton<ISomeInterface>(instance);
Now any attempt to resolve ImplementationOfSomeInterface or ISomeInterface will both return the instance initialized here.

Kotlin reflection on object instance

I've been trying some stuff from kotlin.reflection during my project, and got stuck on something what occurs to me as hard to understand, I have declared object as follows:
object WebsiteMapping
{
const val ADMIN = "/admin"
}
once I call:
Arrays
.stream(WebsiteMapping::class.java.declaredFields)
.forEach { field -> println(field.type) }
what I get is:
class java.lang.String
class mapping.WebsiteMapping
When I looked a little bit into what is behind declaredFields invocation I grasped why it works as it is, but is there any convenient way of taking only declared consts within that object without getting also root of the whole structure?
The field with the type class mapping.WebsiteMapping is, basically, not the root of the structure but a special field generated in the object type that holds the reference to the singleton object.
In Kotlin, this field is named INSTANCE by convention. You can therefore filter the fields that you get from the class as follows:
WebsiteMapping::class.java.declaredFields
.filter { it.name != "INSTANCE" }
.forEach { println(it.type) }
Another solution is to switch from java.reflect.* to the Kotlin reflection API kotlin.reflect (needs a dependency on the kotlin-reflect module), which automatically filters the property:
WebsiteMapping::class.memberProperties
.forEach { println(it.returnType) }

Creating a new instance of a KClass

I have a Kotlin class whose primary (and only) constructor is empty.
I have a reference to this class:
val kClass: KClass<MyClass> = MyClass::class
How do I create an instance of this class using reflection?
In Java I would do myClass.newInstance() but it seems in Kotlin I need to find the constructor first:
kClass.constructors.first().call()
I have seen mention of primaryConstructor in some bug reports but it's not showing up in my IDE.
In your case, Java reflection might be enough: you can use MyClass::class.java and create a new instance in the same way as you would with Java reflection (see #IngoKegel's answer).
But in case there's more than one constructor and you really need to get the primary one (not the default no-arg one), use the primaryConstructor extension function of a KClass<T>. It is a part of Kotlin reflection, which is not shipped within kotlin-stdlib.
To use it, you have to add kotlin-reflect as a dependency, e.g. a in Gradle project:
dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
Assuming that there is ext.kotlin_version, otherwise replace $kotlin_version with the version you use.
Then you will be able to use primaryConstructor, for example:
fun <T : Any> construct(kClass: KClass<T>): T? {
val ctor = kClass.primaryConstructor
return if (ctor != null && ctor.parameters.isEmpty())
ctor.call() else
null
}
You can use the Java class to create new instance:
MyClass::class.java.newInstance()
For those checking this question now, since Kotlin 1.1 there's also createInstance() extension method on KClass
Much like the accepted answer, this function works only in case class has an empty constructor or constructor with all default arguments.
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect.full/create-instance.html
Expanding on Alexeys Answer, to include a primary constructor call with parameters:
/* Example class with no-args constructor */
class MyClass
/* Example class requiring parameters */
class MyClassWithParams(parameter1: String, parameter2: MyClass)
val myKClass: KClass<MyClass> = MyClass::class
val myKClassWithParameters: KClass<MyClassWithParams> = MyClassWithParams::class
/* We can create an object by calling createInstance when no constructor parameters are required as explained in other answers. */
val myObject: MyClass = myKClass.createInstance()
/* To create an object with parameters, we need to get the constructor first, and call it with the parameters instead, similarly to how we would do in Java. */
val myObjectWithParameters: MyClassWithParams? =
myKClassWithParameters.primaryConstructor?.call(
"StringParameter", myObject
)

strongly typed sessions in asp.net

Pardon me if this question has already been asked. HttpContext.Current.Session["key"] returns an object and we would have to cast it to that particular Type before we could use it. I was looking at various implementations of typed sessions
http://www.codeproject.com/KB/aspnet/typedsessionstate.aspx
http://weblogs.asp.net/cstewart/archive/2008/01/09/strongly-typed-session-in-asp-net.aspx
http://geekswithblogs.net/dlussier/archive/2007/12/24/117961.aspx
and I felt that we needed to add some more code (correct me if I was wrong) to the SessionManager if we wanted to add a new Type of object into session, either as a method or as a separate wrapper. I thought we could use generics
public static class SessionManager<T> where T:class
{
public void SetSession(string key,object objToStore)
{
HttpContext.Current.Session[key] = objToStore;
}
public T GetSession(string key)
{
return HttpContext.Current.Session[key] as T;
}
}
Is there any inherent advantage in
using
SessionManager<ClassType>.GetSession("sessionString")
than using
HttpContext.Current.Session["sessionString"] as ClassType
I was also thinking it would be nice
to have something like
SessionManager["sessionString"] = objToStoreInSession,
but found that a static class cannot have an indexer. Is there any other way to achieve this ?
My thought was create a SessionObject which would store the Type and the object, then add this object to Session (using a SessionManager), with the key. When retrieving, cast all objects to SessionObject ,get the type (say t) and the Object (say obj) and cast obj as t and return it.
public class SessionObject { public Type type {get;set;} public Object obj{get;set;} }
this would not work as well (as the return signature would be the same, but the return types will be different).
Is there any other elegant way of saving/retrieving objects in session in a more type safe way
For a very clean, maintainable, and slick way of dealing with Session, look at this post. You'll be surprised how simple it can be.
A downside of the technique is that consuming code needs to be aware of what keys to use for storage and retrieval. This can be error prone, as the key needs to be exactly correct, or else you risk storing in the wrong place, or getting a null value back.
I actually use the strong-typed variation, since I know what I need to have in the session, and can thus set up the wrapping class to suit. I've rather have the extra code in the session class, and not have to worry about the key strings anywhere else.
You can simply use a singleton pattern for your session object. That way you can model your entire session from a single composite structure object. This post refers to what I'm talking about and discusses the Session object as a weakly typed object: http://allthingscs.blogspot.com/2011/03/documenting-software-architectural.html
Actually, if you were looking to type objects, place the type at the method level like:
public T GetValue<T>(string sessionKey)
{
}
Class level is more if you have the same object in session, but session can expand to multiple types. I don't know that I would worry about controlling the session; I would just let it do what it's done for a while, and simply provide a means to extract and save information in a more strongly-typed fashion (at least to the consumer).
Yes, indexes wouldn't work; you could create it as an instance instead, and make it static by:
public class SessionManager
{
private static SessionManager _instance = null;
public static SessionManager Create()
{
if (_instance != null)
return _instance;
//Should use a lock when creating the instance
//create object for _instance
return _instance;
}
public object this[string key] { get { .. } }
}
And so this is the static factory implementation, but it also maintains a single point of contact via a static reference to the session manager class internally. Each method in sessionmanager could wrap the existing ASP.NET session, or use your own internal storage.
I posted a solution on the StackOverflow question is it a good idea to create an enum for the key names of session values?
I think it is really slick and contains very little code to make it happen. It needs .NET 4.5 to be the slickest, but is still possible with older versions.
It allows:
int myInt = SessionVars.MyInt;
SessionVars.MyInt = 3;
to work exactly like:
int myInt = (int)Session["MyInt"];
Session["MyInt"] = 3;

Resources