пятница, 13 марта 2020 г.

Complains about Entity Framework Core


1. Your code compiles without errors. But runtime exceptions await you.

The LINQ expression could not be translated.

2. Your code compiles and works. And you wanted to change the database provider. Your code is still compiling, but runtime exceptions await you.

3. Everything is tracked by default. If you turn off tracking, the navigation stops working.

Lazy-loading is not supported for detached entities

4. "Update" method sets all fields as modified.

5. When db context is disposed?

6. No automatic migrations. Or at least the merger of migrations.

7. This should not exist:
context.Entry(existingBlog).CurrentValues.SetValues();
context.ChangeTracker.TrackGraph()

четверг, 14 ноября 2019 г.

What I really need in C#

As for 14.11.2019
  • Every method and property are async by default and awaited by default.
  • Everything immutable by default, with hardcore compile-time optimizations.
  • Current Type generic constraint.
  • Nullable reference types behave like nullable struct types. E.g. HasValue, Value etc. Or vice versa.
  • Generic type inference of the generic type constructor.
  • Type inference for parameters, return types, fields.
  • Something to do with polymorphism hell. (Combination of required parameter names with default values or DTO as parameters.)
  • Dangling comma in parameters list.
  • Compile-time rewriting of the Linq queries to simple foreach, if etc.
  • Microtypes and record types support.

четверг, 12 января 2017 г.

Existential types workaround in C#

I need to create a generic tree, where children nodes can have different types.
class Node<T>
{
   public T Value { get; }
   public Node<?>[] Children { get; }

   public Node(T value, Node<?>[] children)
   {
       Value = value;
       Children = children;
   }
}
And a simple depth calculator.
public static int Depth(Node<?> node) =>
   1 + node.Children.Select(Depth)
                    .DefaultIfEmpty().Max();
But what can I put instead of wildcard '?' in C# ?
It cannot be 'object' because I want to restrict children of the same parent to have the same type.
It cannot be 'T' or 'T2' because different nested levels may have different types.
Type information is not used in Depth method, so I can use existential types here. But, unfortunately, C# doesn't support them.

This answer on StackOverflow suggested a hint.
∃'x.T<'x> ≡ ∀'z.(∀'x.T<'x> -> 'z) -> 'z
I can simulate existential type using two universal types. They both hide children type from the parent class.
interface IExistentialList
{
    TRet Apply<TRet>(IExistentialFunc<TRet> a);
}

interface IExistentialFunc<TRet>
{
    TRet Apply<T>(Node<T>[] a);
}
Children's type will be stored in implementation class.
class SpecificList<T> : IExistentialList
{
    private Node<T>[] nodes;
 
    public SpecificList(Node<T>[] nodes)
    {
        this.nodes = nodes;
    }
 
    public TRet Apply<TRet>(IExistentialFunc<TRet> a) => a.Apply(nodes);
}
Tree will become.
class Node<T>
{
 public T Value { get; }
 public IExistentialList Children { get; }

 public Node(T value, IExistentialList children)
 {
  Value = value;
  Children = children;
 }
}
Depth function will become a class.
class DepthFunc : IExistentialFunc<int>
{
    public static int Invoke<T>(Node<T> s) =>
        new DepthFunc().Run(s);

    private int Run<T>(Node<T> s) =>
        1 + s.Children.Apply(this);

    public int Apply<T>(Node<T>[] list) =>
        list.Select(Run).DefaultIfEmpty(0).Max();
}
I can use it easily with some helper functions.
public static Node<TP> Create<TPTC>(TP value, params Node<TC>[] array) =>
    new Node<TP>(value, new SpecificList<TC>(array));

public static Node<TP> Create<TP>(TP value) =>
    new Node<TP>(value, new SpecificList<object>(new Node<object>[0]));
 
public static void Main()
{
    var tree = Create(1,
        Create("test1", Create(10.5f)),
        Create("test2"));

    Console.WriteLine(DepthFunc.Invoke(tree));
}

суббота, 21 мая 2016 г.

I created anki overdrive possible tracks generator in C#


It generates all possible tracks that you can build using your pieces.

https://github.com/xiety/AnkiOverdrive

Here are all posible tracks for my own 6 straight and 8 corner pieces (100 tracks):



 Starter kit has only 9 tracks available:


вторник, 1 сентября 2015 г.

Visual Studio Single File Generator to run roslyn Syntax Walker and generate additional members

I've created a custom tool for Visual Studio that runs your custom roslyn Syntax Walker to generate additional members. This is my way for emulating the lack of metaprogramming using roslyn in C#.

https://github.com/xiety/RoslynGenerator

For example, I've used it for generating Identity Value Types:

In AccountId.cs file:

[MetaIdentity("account")]
public partial struct AccountId : IIdentity
{
}

Assign RoslynGenerator as Custom Tool for this file, and it will generate AccountId.gen.cs file for you with some boilerplate code:


public partial struct AccountId
{
        private const string Prefix = "account-";
        private readonly string _value;

        public AccountId(string value){ _value = value; }

        public AccountId(long value)
                : this(Prefix + value){}

        public override bool Equals(object obj)
        {
            if (obj == null || obj.GetType() != typeof(AccountId)) return false;
            return _value == ((AccountId)obj)._value;
        }

        public override string ToString() => _value;
        public static implicit operator AccountId(string value) => new AccountId(value);
        public static implicit operator string (AccountId id) => id._value;
        public static bool operator ==(AccountId a, AccountId b) => a._value == b._value;
        public static bool operator !=(AccountId a, AccountId b) => !(a == b);
        public override int GetHashCode() => _value.GetHashCode();
}

To make this transformation RoslynGenerator finds in your project references class called MetaSyntaxWalker and runs it's Generate method dynamically passing SemanticModel and SyntaxRoot of current file.

понедельник, 31 августа 2015 г.

Visual Studio Extension to run all custom tools for all solution files on every build

I've created an extension to Visual Studio that runs all custom tools on every build.

https://github.com/xiety/RunCustomToolsOnBuild

Lessons learned:

1. Make sure that "Copy local" property is set to "False" on every project reference. Or extension would not be installed. Without displaying any error messages.

2. If breakpoints do not work, you must change Project property "Include Debug Symbols in Local Deployment" to "True"

3. If you get error VSSDK1031: Extension '...' could not be found. Try to reset Exp profile and restart VS.
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe" /RootSuffix Exp /setup

4. Check extension files after VS project build in:
c:\users\{user}\appdata\local\microsoft\visualstudio\14.0exp\extensions\

среда, 17 июня 2015 г.

Prevent implicit casting from null keyword to struct when implicit conversion from string is defined

If your struct has defined implicit conversion from string, then null keyword will be implicitly handled as string and there will be no compiler error.

To prevent this you could define second implicit conversion from any other reference type. Then implicit casting from null keyword becomes ambiguous and will produce error:

Argument type 'null' is not assignable to parameter type 'MyType'

Exactly what we wanted.

вторник, 9 ноября 2010 г.

C# custom tool file generation based on C# template file

Download sources and vsix from CompileGenerator.Codeplex.com

C# custom tool file generation based on C# template file. Write C# Code wich will be converted to another more detailed, specific C# code.
Features
- Build-in VS2010 .cs file Syntax highlighting and IntelliSense in template
- No need to learn new language nor syntax for template writers. C# your best friend here.
- Modifying generation code without restarting VS (code compiled in another domain)
- Code that writes code, it’s fun
- Preprocessed t4 templates for code generator
- No XML
- No more Dependency Property mess in your code
How it’s work
1. Add a new simple .cs file into your project

2. Write code that may describe some other code you need right here in your project (Dependency Properties, DTO or CQRS Commands for example)

using Xiety.DtoGenerator;

public class Nodes : DtoData
{
    public void Run()
    {
        Namespace("Xiety.GenerationSample");

        Class("TableNode""QueryNode")
            .Property("string""TableName");

        Class("OnNode")
            .ListProperty("ExpressionNode""Expressions");

        Class("QueryNode", abstr: true)
            .Property("QueryNode""Query")
            .Property("String""Alias");

        Class("ExpressionNode")
            .Property("string""Content");

        Class("JoinNode""QueryNode")
            .Property("OnNode""On")
            .Property("QueryNode""Left")
            .Property("QueryNode""Right");

        Class("FilterNode""QueryNode")
            .Property("WhereNode""Where");

        Class("WhereNode")
            .ListProperty("ExpressionNode""Expressions");
    }
}
3. Change custom tool settings of your file

4. Save your file and immediately get the new .cs file right in place with generated results

using System;
using System.Collections.Generic;

namespace Xiety.GenerationSample
{
    public class TableNode : QueryNode
    {
        public string TableName { getset; }

    }

    public class OnNode
    {
        public IList<ExpressionNode> Expressions { getset; }

        public OnNode()
        {
            Expressions = new List<ExpressionNode>();
        }
    }

    public abstract class QueryNode
    {
        public QueryNode Query { getset; }
        public String Alias { getset; }

    }

    public class ExpressionNode
    {
        public string Content { getset; }

    }

    public class JoinNode : QueryNode
    {
        public OnNode On { getset; }
        public QueryNode Left { getset; }
        public QueryNode Right { getset; }

    }

    public class FilterNode : QueryNode
    {
        public WhereNode Where { getset; }

    }

    public class WhereNode
    {
        public IList<ExpressionNode> Expressions { getset; }

        public WhereNode()
        {
            Expressions = new List<ExpressionNode>();
        }
    }

}

5. Tune your generator template and code to produce different results
<#@ template language="C#" #>
<#@ import namespace="System.Linq" #>
using System;
using System.Collections.Generic;

<# if (NotEmpty(Data.FileNamespace)) { #>
namespace 
<#= Data.FileNamespace #>
{
<# } #>
<# foreach (var cls in Data.Classes) { #>
    public
<#= If(cls.Abstract, " abstract"#> class <#= cls.Name #><#= IfNotNull(cls.Extends, " : {0}"#>
    {
<# foreach (var property in cls.Properties) { #>
        public 
<#= property.TypeName #> <#= property.Name #> { get; set; }
<# } #>
<# foreach (var property in cls.ListProperties) { #>
        public IList<
<#= property.TypeName #><#= property.Name #> { get; set; }
<# } #>

<# if (cls.ListProperties.Any()) { #>
        public 
<#= cls.Name #>()
        {
<# foreach (var property in cls.ListProperties) { #>
            
<#= property.Name #> = new List<<#= property.TypeName #>>();
<# } #>
        }
<# }//constructor #>
    }

<# } #>
<# if (NotEmpty(Data.FileNamespace)) { #>
}
<# } #>

C# DSL Language to describe template

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace Xiety.DtoGenerator
{
    public class DtoData
    {
        public string FileNamespace { getset; }
        public List<ClassNode> Classes { getset; }

        public DtoData()
        {
            Classes = new List<ClassNode>();
        }

        public void Namespace(string nspace)
        {
            this.FileNamespace = nspace;
        }

        public ClassNode Class(string name, string extends = nullbool abstr = false)
        {

            var cls = new ClassNode(name, extends, abstr);
            this.Classes.Add(cls);
            return cls;
        }
    }

    public class ClassNode
    {
        public bool Abstract { getset; }
        public string Extends { getset; }
        public string Name { getset; }

        public List<PropertyNode> Properties { getset; }
        public List<ListPropertyNode> ListProperties { getset; }

        public ClassNode()
        {
            this.Properties = new List<PropertyNode>();
            this.ListProperties = new List<ListPropertyNode>();
        }

        public ClassNode(string name, string extends, bool abstr)
            : this()
        {

            this.Name = name;
            this.Extends = extends;
            this.Abstract = abstr;
        }

        public ClassNode Property(string type, string name)
        {

            var property = new PropertyNode(type, name);
            this.Properties.Add(property);
            return this;
        }

        public ClassNode ListProperty(string type, string name)
        {

            var property = new ListPropertyNode(type, name);
            this.ListProperties.Add(property);
            return this;
        }
    }

    public class PropertyNode
    {
        public string TypeName { getset; }
        public string Name { getset; }

        public PropertyNode(string typeName, string name)
        {

            this.TypeName = typeName;
            this.Name = name;
        }
    }

    public class ListPropertyNode
    {
        public string TypeName { getset; }
        public string Name { getset; }

        public ListPropertyNode(string typeName, string name)
        {

            this.TypeName = typeName;
            this.Name = name;
        }
    }
}

Download sources and vsix from CompileGenerator.Codeplex.com