I started learning swift and just learned about associated types and opaque types.
Take a look at the following example -
protocol Appendable {
associatedtype Item
var collection: [Item] { get set }
func Append(_ item: Item)
}
For which an implementation would be -
struct IntArray: Appendable {
typealias Item = Int
var collection: [Int] = []
func append(_ item: Int) {
collection.append(item)
}
}
I understand that any class that conforms to Appendable could declare it’s own type for Item and use that type, thus making the Appendable protocol more generic.
My question is, if and how is this any different from a generic interface in, let’s say, C#? (I come from a C# background). Also, if it is different, is there any reason that they chose to implement generic protocols that specific way?
Like so -
public interface IAppendable<Item> {
List<Item> Collection { get; }
void Append(Item item);
}
For which an implementation would look like this -
public class IntList: IAppendable<int> {
private List<int> _list = new List<int>();
public List<int> Collection => _list;
public void Append(int item) {
_list.Add(item);
}
}
Related
I'm trying to make reusable includes and it currently works when I have specific concrete root entity. But let's say I have structure like this:
public class A
{
public B NavigationB { get; set; }
}
public class B
{
public C NavigationC { get; set; }
}
public class C
{
}
And my include extensions
public static class IncludeExtensions
{
public static IQueryable<B> MyIncludesB(this IQueryable<B> query)
{
return query.Include(q => q.NavigationC);
}
public static IQueryable<A> MyIncludesA(this IQueryable<A> query)
{
return query.Include(q => q.NavigationB)
.MyIncludesB(); // how can I implement this
}
}
Basically everything is okay if I have single root e.g. A, but what if I want to do fetch using root B? The idea is to then include everything required for B, but when using A as root then include everything for A, and when including B, reuse MyIncludesB.
I'm not sure if this is possible because include is returning IIncludableQueryable<A, B>, but if anyone has any suggestions, feel free to help!
I think there are numerous possibilities.
My first idea would be to encapsulate the property expression:
public static class IncludeExtensions
{
public static Expression<Func<B, C>> MyIncludeListB()
{
return q => q.NavigationC;
}
public static Expression<Func<A, B>> MyIncludeListA()
{
return q => q.NavigationB;
}
public static IQueryable<B> MyIncludesB(this IQueryable<B> query)
{
return query.Include(MyIncludeListB());
}
public static IQueryable<A> MyIncludesA(this IQueryable<A> query)
{
return query.Include(MyIncludeListA()).ThenInclude(MyIncludeListB());
}
}
As you can see you can pass Expression<Func<B, C>> to the method Include
My second idea is to implement include with strings .Include(string):
public static class IncludeExtensions2
{
public static IEnumerable<string> MyIncludeListB()
{
return "NavigationC".Split(";");
}
public static IEnumerable<string> MyIncludeListA()
{
return "NavigationB;NavigationB.NavigationC".Split(";");
}
public static IQueryable<B> MyIncludesB(this IQueryable<B> query)
{
foreach (var i in MyIncludeListB())
{
query = query.Include(i);
}
return query;
}
public static IQueryable<A> MyIncludesA(this IQueryable<A> query)
{
foreach (var i in MyIncludeListA())
{
query = query.Include(i);
}
return query;
}
}
As you can see you can pass string to the method Include. You can pass the complete chain of navigation properties.
If you want to implement more than one navigation property you have to amend both code examples accordingly.
There are already some questions and answers like yours:
Easy: Entity Framework - Include Multiple Levels of Properties
Hard: Multiple Includes() in EF Core
I want to have a generic way of doing something like in Swift 3:
public protocol Callable {
associatedtype In : CVarArg
associatedtype Out : CVarArg
}
public struct IntCallable : Callable {
public typealias In = Int
public typealias Out = Double
public typealias FunctionalBlock = #convention(c) (In) -> Out
public func call(_ block: FunctionalBlock) { /* do stuff */ }
}
So I'd like it to look more like this:
public protocol Callable {
associatedtype In : CVarArg
associatedtype Out : CVarArg
typealias FunctionalBlock = #convention(c) (In) -> Out
}
public struct IntCallable : Callable {
public typealias In = Int
public typealias Out = Double
}
public extension Callable {
public func call(_ block: FunctionalBlock) { /* do stuff */ }
}
However, I get the error:
'(Self.In) -> Self.Out' is not representable in Objective-C, so it cannot be used with '#convention(c)'
Is there any constraint I can place on the In/Out associatedtypes that will allow my to declare the generic form of the FunctionalBlock? It works fine without #convention(c), but I need it in order to form a C function call.
This is not currently possible in Swift, due to the how Swift manages values passed as protocols, and CVarArg is a protocol.
What happens behind the scenes is that when passing a value under the umbrella of a protocol, the Swift compiler creates an existential container that wraps the value, a value which is transparently unwrapped at the callee site.
So basically your block actually looks something like this:
typealias FunctionalBlock = #convention(c) (Container<In>) -> Container<Out>
Due to this behind-the-scenes transform, you're not passing values that can be represented in C, thus the error you get.
This is very similar to other protocol related issues, like the famous Protocol doesn't conform to itself?.
Your best bet would be to add overloads for all types that conform to CVarArg, since this is a finite and unchangeable list.
How to confirm to protocols that declares properties of other protocols in Swift?
There is a protocol GKGameModel in which its implementers need to have a properties conforming to a protocol
public protocol GKGameModel {
// ...
public var players: [GKGameModelPlayer]? { get }
public var activePlayer: GKGameModelPlayer? { get }
// ...
}
public protocol GKGameModelPlayer {
// ...
}
Now, suppose I have a class Player and GameModel that conforms to the above protocols
class Player : NSObject, GKGameModelPlayer {
//...
}
class GameModel : NSObject, GKGameModel {
//...
public var players: [Player]?
public var activePlayer: Player?
}
Now the above code doesn't compile and the error messages (among others) were:
protocol requires property 'activePlayer' with type 'GKGameModelPlayer?'; do you want to add a stub?
candidate has non-matching type 'Player?'
However the Player class conforms to protocol GKGameModelPlayer, hence it should confirm just fine. How can I get this to compile?
Strangely Objective-C deals with this just fine – take a look at the FourInARow example code which does something like this.
The protocol requires that the properties be typed exactly as shown. In other words, an array of GKGameModelPlayers and a single optional GKGameModelPlayer?. If your Player type conforms to the protocol, then an array of Players can be passed to the protocol property if casted / typed as [GKGameModelPlayer].
But the requirement here is not, for example, an activePlayer property that has a type that conforms to GKGameModelPlayer, but rather an activePlayer property that references an instance that it typed as / cast as a GKGameModelPlayer.
I.e. this would fix the error:
class GameModel : NSObject, GKGameModel {
//...
public var players: [GKGameModelPlayer]?
public var activePlayer: GKGameModelPlayer?
}
players and activePlayer property has a type that conforms to GKGameModelPlayer. So just change it to GKGameModelPlayer type instead of Player
class GameModel : NSObject, GKGameModel {
//...
public var players: [GKGameModelPlayer]?
public var activePlayer: GKGameModelPlayer?
}
I was thinking to generate EntityTypeConfiguration dynamically from run time and i don't want any EF dependency in Models[That is why i avoid Data Annotation].
So I declare a custom attribute(or can be any configuration file later on)
[AttributeUsage(AttributeTargets.Property, AllowMultiple=true )]
public class PersistableMemberAttribute : Attribute
{
public bool Iskey;
public bool IsRequired;
public bool IsIgnored;
public bool IsMany;
public string HasForeignKey;
public bool PropertyIsRequired;
public bool PropertyIsOptional;
}
And here is one of my Models is look like:
public class Blog
{
[PersistableMember(Iskey=true)]
public Guid BlogId { get; set; }
[PersistableMember(PropertyIsRequired = true)]
public string Name { get; set; }
public string Url { get; set; }
[PersistableMember(IsIgnored=true)]
public int Rating { get; set; }
[PersistableMember(IsMany =true)]
public ICollection<Post> Posts { get; set; }
}
Now I am going to write a generic EntityTypeConfiguration , which will create the configuration dynamically on run time based on the attribute values :
public class GenericEntityConfiguration<T> : EntityTypeConfiguration<T> where T : class
{
public GenericEntityConfiguration()
{
var members = typeof(T).GetProperties();
if (null != members)
{
foreach (var property in members)
{
var attrb= property.GetCustomAttributes(typeof( PersistableMemberAttribute ),false).OfType<PersistableMemberAttribute>();
if (attrb != null && attrb.Count() > 0)
{
foreach (var memberAttributute in attrb)
{
if (memberAttributute.Iskey || memberAttributute.IsIgnored)
{
var entityMethod = this.GetType().GetMethod("Setkey");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.IsRequired)
{
var entityMethod = this.GetType().GetMethod("SetRequired");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.PropertyIsRequired || memberAttributute.PropertyIsOptional)
{
var entityMethod = this.GetType().GetMethod("SetPropertyConfiguration");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
}
}
}
}
}
public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.PropertyIsRequired)
{
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
}
if (attribute.PropertyIsOptional)
{
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
}
}
public void Setkey<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.Iskey)
{
this.HasKey<TResult>((Expression<Func<T,TResult>>)lambda);
}
if (attribute.IsIgnored)
{
this.Ignore<TResult>((Expression<Func<T, TResult>>)lambda);
}
}
public void SetRequired<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) where TResult : class
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.IsRequired)
{
this.HasRequired<TResult>((Expression<Func<T, TResult>>)lambda);
}
}
}
But i got the compilation error of
Error 1 The type 'TResult' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression>)' D:\R&D\UpdateStorePOC\UpdateStorePOC\Data\GenericEntityConfiguration.cs 63 17 UpdateStorePOC
which for these two statements:
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
that means that I need to put a constraint on my method to restrict it to a value type. In C#, this is done with the ‘struct’ keyword.
public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) Where TResult : struct
But Its not the solution since my property type can be a class e.g string or int, bool double, etc . So it is not at all clear that I can send them into this method. Please help me to solve this issue whether there is any other way to do it.
I don't want any EF dependency in models.
With fluent mapping you're almost there and you won't come any closer. Your attributes, even though intended to be moved to a configuration file, don't make your model any more free of any EF footprint.1 Worse, they only add a second mapping layer (if you like) between your model and EF's mapping. I only see drawbacks:
You still have to maintain meta data for your model, probably not any less than regular fluent mapping and (probably) in awkward manually edited XML without compile-time checking.
You will keep expanding your code to cover cases that EF's mapping covers but yours doesn't yet.2 So it's a waste of energy: in the end you'll basically have rewritten EF's mapping methods.
You'll have to keep your fingers crossed when you want to upgrade EF.
With bugs/problems you're on your own: hard to get support from the community.
So my answer to your question help me to solve this issue would be: use fluent mapping out of the box. Keep it simple.
1 For example, you would still have to use the virtual modifier to enable proxies for lazy loading.
2 Like support for inheritance, unmapped foreign keys, max length, db data type, ... this could go on for a while.
I'm creating MVVM application and in Model section I have simple base abstract class Animal and class Dog which derives from it:
public abstract class Animal
{
public int Age { get; set; }
}
public class Dog : Animal
{
public string Name { get; set; }
}
ViewModel section containts UI-friendly VM classes of them:
public abstract class AnimalVM<T> : ViewModelBase where T : Animal
{
protected readonly T animal;
public int Age
{
get { return animal.Age; }
set
{
animal.Age = value;
OnPropertyChanged("Age");
}
}
protected AnimalVM(T animal)
{
this.animal = animal;
}
}
public class DogVM : AnimalVM<Dog>
{
public string Name
{
get { return animal.Name; }
set
{
animal.Name = value;
OnPropertyChanged("Name");
}
}
public DogVM(Dog dog) : base(dog) { }
}
Suppose I have another VM class which contains ObservableCollection<AnimalVM>. The problem is how to create that kind of property which allow me to store there different types of Animal? I want to achieve something like this:
public class AnimalListVM : ViewModelBase
{
// here is a problem, because AnimalVM<Animal> isn't compatible with DogVM
readonly ObservableCollection<AnimalVM<Animal>> animals;
public ObservableCollection<AnimalVM<Animal>> Animals
{
get { return animals; }
}
public AnimalListVM(IList<Animal> animals)
{
//this.animals = ...
}
}
I can change ObservableCollection<AnimalVM<Animal>> property to ICollection property and then create list of AnimalVM using some dictionary Animal -> AnimalVM wrapper and Activator.CreateInstance() - it works but when I try to extend AnimalListVM adding another property SelectedAnimal which will be binded in sample View to e.g. DataGrid control I have another problem with type of that kind of property SelectedItem. It can't be of type AnimalVM<Animal> because when I have DogVM object in my Collection it won't fit with this and throw an exception.
Everything will be clear if only I had non-generic AnimalVM but I don't want to copy and paste similar properties in every DogVM, CatVM, BirdVM class derived from AnimalVM. How can I achieve this?
Ok, I've found a solution and of course it's very simple: just create another, non-generic abstract base class for your generic abstract base class and then derive your generic class from that newly created non-generic class. In that case you also must rewrite properties from non-generic class to generic class (to be more specific override them), but you do this only once, so you don't have to copy and paste the same code in every generic derived ViewModel (in our example in every DogVM, CatVM, BirdVM, etc.).