Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

2022-12-11

Intertwine

The Intertwine Logo, by michael.gr

Abstract

A mechanism is described for automatically converting method invocations of any programmatic interface into a single-method normal form and converting back to invocations of the original interface, so that general-purpose operations can be performed on the normal form without explicit knowledge of the interface being invoked. Implementations are provided for C# and for Java.

2021-02-12

SVG in WPF

My notes on how to use SVG graphics in a WPF application


The Goal


The goal is to be able do do things like this:

    <Button Content="{StaticResource mySvgImage}">

... where mySvgImage somehow stands for a vector image that has somehow been obtained from an SVG file.  

The solution must not involve any proprietary, closed-source libraries.

Naturally, we want one of the following:

  • either directly include SVG files into our application as resources, or, if that is not possible, then 
  • have an "asset pipeline" approach where our SVG files are automatically converted during build into some format which is suitable for inclusion as a resource.

2013-02-21

C# Blooper №14: Weird / annoying interface method visibility rules.


Before reading any further, please read the disclaimer.

As it turns out, an explicit interface method implementation in C# must be tied to the base-most interface to which it belongs; it cannot be tied to a descendant interface.

namespace Test14
{
    class Test
    {
        interface A
        {
            void F();
        }

        interface B: A
        {
        }

        class C: B
        {
            void A.F() //OK
            {
            }

            void B.F() //error CS0539: 'B.F' in explicit interface declaration is not a member of interface
            {
            }
        }
    }
}

Well, sorry, but... it is.

-

2013-02-05

C# Blooper №13: Stack and Queue do not implement ICollection


Before reading any further, please read the disclaimer.

This is a blooper of the Common Language Runtime (CLR), not of the language itself: Stack<T> and Queue<T> derive from ICollection, but not from ICollection<T>, so they do not support the Remove( T ) method! Why, oh why?

-

2013-01-25

C# Blooper №12: 'Where' constraints not included in method signatures


Before reading any further, please read the disclaimer.

When writing generic methods in C#, it is possible to use the 'where' keyword to specify constraints to the types that the generic parameters can take. Unfortunately, these constraints cannot be used for resolving overloaded methods. Case in point:

namespace Test12
{
    class Test
    {
        public static bool Equals<T>( T a, T b ) where T: class
        {
            return object.Equals( a, b );
        }

        public static bool Equals<T>( T a, T b ) where T: struct //error CS0111: Type 'Test' already defines a member called 'Equals' with the same parameter types
        {
            return a.Equals( b );
        }
    }
}

-

2013-01-14

C# Blooper №11: Zero to Enum conversion weirdness


Before reading any further, please read the disclaimer.

When you assign an enum to int, you have to cast it. That's good. When you assign an int to enum, you also have to cast it. That's also good. But if you assign zero to an enum, you don't have to cast it! Go figure.

namespace Test11
{
    class Test
    {
        public enum myenum
        {
            a, b, c
        }

        void test_myenum( myenum f, int i )
        {
            i = (int)myenum.a; //need to cast; that's good.
            f = (myenum)5; //need to cast; that's still good.
            f = 0; //wtf? no need to cast?
        }
    }
}

-

2013-01-08

C# Blooper №10: Switch statements are not properly formatted.


Before reading any further, please read the disclaimer.

This is rather a Microsoft Visual Studio blooper than a Microsoft C# blooper: When formatting source code, Visual Studio offers an "indent case contents" option, but you will only find it useful if you happen to have a crooked notion as to how switch statements should be formatted. The one and only normal form of formatting switch statements is not supported.

namespace Test10
{
    class Test
    {
        void statement() { }

        void test( int a )
        {
            /* with "indent case contents" option selected: */
            switch( a )
            {
                case 42:
                    /* this is not properly indented */
                    {
                        statement();
                        break;
                    }
                default:
                    /* this is properly indented */
                    statement();
                    break;
            }

            /* with "indent case contents" option deselected: */
            switch( a )
            {
                case 42:
                /* this is properly indented */
                {
                    statement();
                    break;
                }
                default:
                /* this is not properly indented */
                statement();
                break;
            }

            /* the normal way of indenting cannot be achieved: */
            switch( a )
            {
                case 42:
                {
                    statement();
                    break;
                }
                default:
                    statement();
                    break;
            }
        }
    }
}

I know, you might disagree that my way of formatting switch statements is in any way 'normal'. So, in your case, let us agree on this: my way of formatting switch statements, whether you like it or not, is in perfect accordance to the way I format the rest of my code; and since Visual Studio allows me to precisely describe my coding style, it should also allow for a switch statement style that matches the rest of my code.

-

2013-01-07

C# Blooper №9: Annoying case statement fall-through rules.


Before reading any further, please read the disclaimer.

Overall, C# takes an approach which is far more friendly to novice programmers than its predecessors, C and C++ were. For example, in the case of switch statements, C# does not allow the old, error-prone style of C and C++ where you could simply fall through from one case statement to the following one; instead, at the end of each case statement C# requires either a break statement, or a goto statement to explicitly jump to another label. That's all very nice and dandy, except for one thing: C# requires a break or goto even at the last case statement of a switch statement!

namespace Test9
{
    class Test
    {
        void statement() { }

        void wtf_is_it_with_falling_through_the_last_case_label( int a )
        {
            switch( a )
            {
                case 42:
                    statement();
                    break;
                default:
                    statement();
                    break; //Need this 'break' or else: CS0163: Control cannot fall through from one case label ('default:') to another
            }
        }
    }
}

I mean, seriously, WTF?

-

2013-01-04

C# Blooper №8: No warnings for conditions that are always true/false


Before reading any further, please read the disclaimer.

The Microsoft C# compiler does not issue 'condition is always true' and 'condition is always false' warnings. Perhaps these warnings are not particularly meaningful in Java, which lacks conditional compilation directives, and therefore if( true ) and if( false ) are the only means of achieving conditional compilation; but in C#, which has special conditional compilation directives, conditions which are always true or always false are invariably so by mistake; therefore, these warnings would indeed be meaningful, and useful.

namespace Test8
{
    class Test
    {
        void statement() { }

        void test()
        {
            if( true ) //no warning about 'condition is always true'.
                statement();

            while( false ) //no warning about 'condition is always false', even though the compiler obviously knows what's going on, since the following warning is issued:
                statement(); //warning CS0162: Unreachable code detected 
        }
    } 
}


For more information see Why the Microsoft C# compiler lacks many useful warnings.

-

C# Blooper №7: No warnings about unused private methods.


Before reading any further, please read the disclaimer.

If you have a private method which is never used, you will not be given a warning about it by the Microsoft C# compiler. This means that your app will likely get shipped with unnecessary chunks of code in it, some of them possibly containing string litterals that were never meant to make it out of the development environment, or even requiring libraries to be linked which were never meant to be required on the field.

namespace Test7
{
    class Test
    {
        private void unused() //no warning about unused private method.
        {
        }
    }
}

For more information see Why the Microsoft C# compiler lacks many useful warnings.

-

2012-11-29

C# Blooper №6: No warnings about unused parameters.


Before reading any further, please read the disclaimer.

One common mistake that programmers make is to forget to make use of a parameter to a method. This can lead to quite subtle bugs that are hard to track down and correct.

Now, other language compilers are kind enough to warn the programmer that a parameter is unused, and they also allow temporary suppression of the warning for the rare case when such lack of use is legitimate. But not so in Visual C#. If you forget to use a parameter in Visual C#, you will not know unless you run the "Code Analysis" tool on it.

namespace Test6
{
    class Test
    {
        void moo( int a ) //no warning about unused parameter 'a'.
        {
        }
    }
}


For more information see Why the Microsoft C# compiler lacks many useful warnings.

-

2012-11-13

Why the Microsoft C# compiler lacks many useful warnings

As my C# Bloopers series of articles shows, the Microsoft C# compiler fails to issue many useful warnings which one would reasonably expect from a decent compiler of any language, and which are in fact readily and lavishly issued by Java compilers.

After all these years that the Microsoft C# compiler has been maturing, one cannot help but postulate that there are alterior motives behind this continued state of misery with respect to warnings. For lo and behold, it just so happens that the "Ultimate" (most feature-packed and most outrageously expensive) edition of Microsoft Visual Studio contains a "Code Analysis" feature, which is capable of issuing hundreds of different types of warnings, ranging from the pedantic to the arcane, and including most, if not all, of the missing warnings that I am discussing here.

Now, besides the fact that the Code Analysis feature comes at a considerable additional cost, it is also very cumbersome to use on a frequent basis, since it has been built as a separate product feature, instead of having been integrated into the compiler. For one thing, it is very slow. Another thing is that it is very spammy: we are talking about multiple warnings for every single line of code here, most of which are useless, and the first thing you need to do about them is to turn them off. And there are several dozen warnings to turn off. 

This cumbersomeness makes the Code Analysis feature unsuitable for use in the instant builds which developers tend to perform every few minutes or so, and more suitable to use as a separate code-quality-assurance step to be performed once or twice during the entire development process of a product, or at best on nightly builds. Unfortunately, it is precisely on instant builds that the warnings I am talking about in these articles are most useful. Better yet, most of these warnings are useful in real-time, while typing the code, in the form of yellow curly underlines. For example, as a developer, I want to know that a parameter to a method I have just written goes unused before I even proceed to start coding the next method, because it most probably means that I forgot something or I did something wrong. This information is useful not tomorrow, not in a couple of months, but right now.

So, what has probably happened here is that the Microsoft C# compiler team was told by Microsoft's marketing department to intentionally cripple the C# compiler and make it less useful to all of us, by moving some of the functionality which rightfully belongs to it into some other module, so that their premium "Ultimate" product can have a raison d'être.

I bet you that Balmer is behind this.

2012-11-12

C# Blooper №5: Lame/annoying variable scoping rules, Part 2


Before reading any further, please read the disclaimer.

In light of the previous blooper, this one is more of a confusing error message than an actual new blooper. What I am doing below is that I am declaring a field within a class, I am accessing that field from within a method, and further down within the same method I am declaring a new local variable with the same name as the field. Now, C# will not allow me to declare that local variable because it has the same name as the field, but that's not where I am receiving the error. Instead, the error is given when accessing the field. If you only read the first sentence of the error message, it does not make any sense at all. If you bother also reading the second sentence, it gives you a hint as to the real problem. Now, that's not very cool.

namespace Test5
    {
        public class Test
        {
            public int a;

            void foo()
            {
                for( int i = 0;  i < 10;  i++ )
                {
                    a = 10; //error CS0844: Cannot use local variable 'a' before it is declared. The declaration of the local variable hides the field 'Test5.Test.a'.
                }
                string a = "";
                Console.WriteLine( a );
            }
        }
    }

See also: C# Blooper №4: Lame/annoying variable scoping rules, Part 1
-

2012-11-08

C# Blooper №4: Lame/annoying variable scoping rules, Part 1


Before reading any further, please read the disclaimer.

A variable identifier is, of course, only visible within the scope in which it is declared. This includes nested (child) scopes, but it does not include enclosing (parent) scopes. In C# however, once a variable identifier has been used in a scope, its name is "poisoned", so it cannot be used in enclosing scopes. Take this example:

namespace Test4
{
    class Test
    {
        void test()
        {
            if( this != null )
            {
                object o;
                o = null;
                if( o == this )
                    return;
            }
            object o;  //error CS0136: A local variable named 'o' cannot be declared in this scope because it would give a different meaning to 'o', which is already used in a 'child' scope to denote something else
        }
    }
}

Well, I am sorry, but in the above case the new variable named 'o' would most definitely *not* give a different meaning to the 'o' which was used in the child scope. It would, if it had been declared before the 'if' statement, but it wasn't. Luckily, if this "feature" was to be removed from the language, it would not break any existing code. So, can we please have this fixed? Pretty please?

See also: C# Blooper №5: Lame/annoying variable scoping rules, Part 2

-

2012-01-06

C# Blooper №3: No warnings about fields having already been initialized.


Before reading any further, please read the disclaimer.

When you declare a member variable and you pre-initialize it at the same time, and then you try to re-initialize it within the constructor without ever making use of its original pre-initialized value, you receive no warning about the field having already been initialized.

namespace Test3 
{  
    public class Test 
    {  
        public readonly string m = "m"; 
        public string n = "n"; 
        private string o = "o"; 
        protected readonly string p = "p"; 
        protected string q = "p"; 
        private string r = "r"; 

        Test() 
        {  
            m = "m2"; //Blooper: no warning about field having already been initialized. 
            n = "n2"; //Blooper: no warning about field having already been initialized. 
            o = "o2"; //Blooper: no warning about field having already been initialized. 
            p = "p2"; //Blooper: no warning about field having already been initialized. 
            q = "q2"; //Blooper: no warning about field having already been initialized. 
            r = "r2"; //Blooper: no warning about field having already been initialized. 
            o.ToLower(); //to prevent Warning CS0414: The field is assigned but its value is never used. 
            r.ToLower(); //to prevent Warning CS0414: The field is assigned but its value is never used. 
        }  
    } 
}  

This means that you may accidentally invoke complex initialization logic twice, unnecessarily wasting memory and clock cycles, and it may also lead to logic errors, if by any chance that initialization logic has side effects which are only meant to occur once. It may also confuse someone reading your code, (or even yourself looking at your code months later,) trying to figure out what's the purpose behind the seemingly repeated initialization, before the realization sinks in that it is simply redundant. Furthermore, if the re-initialization happens to differ from the pre-initialization, a good question arises, asking which one of the two was meant to be the correct one.

It is a pity, because the compiler could warn the programmer against this pitfall.

Also see related post: C# Blooper №2: No warnings about accessing uninitialized members.

-

C# Blooper №2: No warnings about accessing uninitialized members.


Before reading any further, please read the disclaimer.

When you declare a member variable, and then you try to read it from within the constructor without having first initialized it, you receive no warning about accessing an uninitialized member. This happens even if the member is declared as readonly.

namespace Test2  
{  
    public class Test 
    {  
        public readonly string m; 
        public string n; 
        protected readonly string o; 
        protected string p; 
        private readonly string q; 
        private string r; 

        Test() 
        {  
            m.ToUpper(); //Blooper: no warning about accessing uninitialized member. 
            n.ToUpper(); //Blooper: no warning about accessing uninitialized member. 
            o.ToUpper(); //Blooper: no warning about accessing uninitialized member. 
            p.ToUpper(); //Blooper: no warning about accessing uninitialized member. 
            q.ToUpper(); //Blooper: no warning about accessing uninitialized member. 
            r.ToUpper(); //Blooper: no warning about accessing uninitialized member. 
            q = "q"; //to prevent Warning CS0649: Field is never assigned to, and will always have its default value null 
            r = "r"; //to prevent Warning CS0649: Field is never assigned to, and will always have its default value null 
        }  
    } 
}  

Someone might argue that this is behavior is fine because the member in question is guaranteed to contain its default value. First of all, a readonly member containing its default value is completely useless. (See C# Blooper №1: No warnings about uninitialized readonly members when the class is public and the member is public, protected or protected internal.) Secondly, if the compiler is to help the developer catch potential errors and write better code, this is not a valid excuse: a different strategy is necessary.

If the programmer intends the member to contain its default value, then the programmer ought to explicitly state so. Failing to do so ought to imply intention to initialize the member later on, and certainly before any attempt is made to read the member.  This way, the programmer can have it both ways: they can have members pre-initialized to their default values, and they can receive warnings when they fail to initialize members.

Also please note that the compiler is capable of detecting that the value with which a member is being explicitly initialized is the default value for the type of the member, and so it can refrain from emitting any additional code for the assignment; thus, there is no performance issue.

Also see related post: C# Blooper №3: No warnings about fields having already been initialized.

-

2011-12-31

C# Blooper №1: No warnings about uninitialized readonly members when the class is public and the member is public, protected or protected internal.


Before reading any further, please read the disclaimer.

The C# compiler is kind enough to give you a "field is never assigned to" warning if you forget to initialize a readonly member which is private or internal, or if the class in which it is being declared is internal. But if the class is public, and the readonly member is public, protected or protected internal, then no warning for you! Why, oh why?

namespace Test1  
{  
    class Test1 
    {  
#if TRY_IT  
        public readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        protected readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        internal readonly int o; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        private readonly int p; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        protected internal readonly int q; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
         
        Test1() 
        { 
            if( p != 0 ) //To avoid warning 'The field is never used' 
                return; 
        } 
#endif 
    }  
  
    public class Test2 
    {  
#if TRY_IT  
        private readonly int m; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
        internal readonly int n; //OK: warning CS0649: Field is never assigned to, and will always have its default value 0  
 
        Test2() 
        { 
            if( m != 0 ) //To avoid warning 'The field is never used' 
                return; 
        } 
#endif  
        public readonly int o; //Blooper: no warning about field never assigned to.  
        protected readonly int p; //Blooper: no warning about field never assigned to.  
        protected internal readonly int q; //Blooper: no warning about field never assigned to. 
    }  
  
    public sealed class Test3 
    {  
        public readonly int m; //Blooper: no warning about field never assigned to.  
    }  
}  

For a moment you might think "well, a descendant might initialize that member", but that theory does not hold any water, for a number of reasons:
  • Internal classes may also be subclassed, but the compiler does not fail to issue the warning in their case.
  • Sealed classes may not be subclassed, but the compiler fails to issue the warning in their case, as Test3 in the sample code demonstrates.
  • The warning makes sense for the sake of the integrity of the base class regardless of what a derived class may or may not do.
  • Lastly but most importantly, the C# specification expressly prohibits a derived class from initializing a readonly member of a base class. You get Error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer) which, incidentally, is a little bit misleading, because you may be trying to assign the field from within a constructor, only it is the constructor of the wrong class.
According to MSDN Documentation about this warning, the exhibited behavior is to be expected:
Compiler Warning (level 4) CS0649:
Field 'field' is never assigned to, and will always have its default value 'value'
The compiler detected an uninitialized private or internal field declaration that is never assigned a value.
The question is: why?

UPDATE:

I posted this question on StackOverflow, and Eric Lippert himself answered it. The short answer is that it is an oversight of the compiler, but the long answer is also quite interesting and worth reading.
-

C# Bloopers


Please do not get me wrong; C# is awesome. It is the language of my choice, even though I am pretty well versed in C++ and Java. That having been said, it cannot be denied that C# has its share of flaws, too. In this series of posts I am documenting some of them, in no particular order.

Also please note that many of the issues described herein are Visual C# bloopers, not C# bloopers in general.

C# Blooper №1: No warnings about uninitialized readonly members when the class is public and the member is public, protected or protected internal.

C# Blooper №2: No warnings about accessing uninitialized members.

C# Blooper №3: No warnings about fields having already been initialized.

C# Blooper №4: Lame/annoying variable scoping rules, Part 1

C# Blooper №5: Lame/annoying variable scoping rules, Part 2

C# Blooper №6: No warnings about unused parameters.

C# Blooper №7: No warnings about unused private methods.

C# Blooper №8: No warnings for conditions that are always true/false

C# Blooper №9: Annoying case statement fall-through rules.

C# Blooper №10: Switch statements are not properly formatted.

C# Blooper №11: Zero to Enum conversion weirdness

C# Blooper №12: 'Where' constraints not included in method signatures

C# Blooper №13: C# Blooper №13: Stack and Queue do not implement ICollection

C# Blooper №14: Weird / annoying interface method visibility rules.

Stay tuned, there is more to come.
-

2011-10-16

Intertwine: Normalizing Interface Invocations

This post has been superseded by a new post in 2022
See michael.gr - Intertwine


This is a C# project that I did back in 2011. It consists of a (rather informal) white paper which describes the project, and a zip file containing the source code in the form of a Microsoft Visual Studio solution.

Here is the abstract:
A mechanism is proposed for converting (entwining) method call invocations of any interface to a general purpose single-method normal form, and converting back (untwining) from the normal form to interface invocations, so that operations can be performed on the normal form in a way agnostic to the interface being invoked. The normal form is a delegate in C# or a functional interface in Java, realized as object AnyCall( int selector, object[] parameters ). A DotNet implementation is provided in C#, though the discussion also applies to Java.

And here is the table of contents:
  • Abstract (page 1)
  • The Problem (page 1)
    •  Why messages are bad (page 2)
    •  What is missing (page 2)
  • The Solution (page 2)
    • A hand-crafted solution (page 3)
    • Automating with Intertwine (page 6)
  • Appendix 1: A note about Dynamic Proxies (page 6)
  • Appendix 2: An example: Interface multicasts (events) (page 7)
  • Appendix 3: Things to fix (page 8)


Download the white paper: Intertwine v2.1.pdf
Download the source code: Intertwine v2.0.zip