Skip to main content

3 posts tagged with "learn"

View All Tags

· 2 min read

I have hit a corner case of extension methods and LINQ. Today I was declaring some extension methods to make my code more readable.So I created an extension method that gets an object and performs a direct cast:

public static class GeneralExtensions
{
public static T Cast<T>(this object o)
{
return (T)o;
}
}

The intention was to be able to call my direct castings by something like this:

MyObject.CastTo<MyInterface>();

It happens that in the same namespace I have an extension method that has a LINQ expression

using System;
using System.Collections.Generic;
using System.Linq;

public static class EnumExtenstions
{
public static IEnumerable<string> UseLinq(this IEnumerable<object> collection)
{
return (from object value in collection select value.ToString() ).ToList();
}
}

Adding this first extension method to my code base cause the next error

Error   CS1936  Could not find an implementation of the query pattern for source type 'object'.  'Select' not found.

Having both extension methods in different namespaces (and not referred), or rename Cast<T> to something different solves the issue. This is caused for an overlap of the extension methods where the nearest one to the code is the one called.

##How bad Extension Methods over object could go?

This is an extract from the answer of Eric Lippert, regarding the code:

public static class GeneralExtensions
{
public static T Cast<T>(this object o)
{
return (T)o;
}
}

Side Effects of the cast<T>:

  • Cast<int>(123) unnecessarily boxes the int, (int)123 does not.
  • Cast< short >(123) fails but (short)123 succeeds. There is no conversion from a boxed int to a short.
  • Suppose you have a user-defined conversion from Animal to Shape. Cast<Shape>(new Tiger()) fails but (Shape) new Tiger() succeeds.
  • Suppose q is a nullable int that happens to be null. Cast<string>(q) succeeds! But (string)q would fail at compile time
  • Etc

Cast method has some overlap with the real cast operator but is not a substitute for it. To capture the semantics of the cast operator there is a need to use dynamic, which starts the compiler at runtime and does the compile time analysis on runtime types.

· One min read

I have not experiment to much with fluent interfaces. But is something cool especially to make code that is expressive.

public struct Coordenates
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}

public static class CoordenatesExtensions
{

public static Coordenates X(this Coordenates coordenates, double value)
{
coordenates.X = value;
return coordenates;
}

public static Coordenates Y(this Coordenates coordenates, double value)
{
coordenates.Y = value;
return coordenates;
}
public static Coordenates Z(this Coordenates coordenates, double value)
{
coordenates.Z = value;
return coordenates;
}
}

public class Points
{
private Coordenates point;
public Points()
{
point = new Coordenates().X(2.1).Y(2.4).Z(3.2);
}
}

also can be used with some language properties to make it more expressive

public static class GeneralExtensions
{
public static T As<T>(this object o) where T : class
{
return o as T;
}

public static T Cast<T>(this object o)
{
return (T)o;
}

public static bool Is<T>(this object o)
{
return o is T;
}
}

· One min read

When doing complex objects using an object to help the building is welcome.

public class Complex
{
double x;
double y;
double z;

float height;
float width;

string foreground;
string background;

public Complex()
{
x = 1.456;
y = 1.234;
z = 1.789;

height = 10.12;
width = 10.14;

foreground = "#FFF";
background = "#FA1";
}

}

In this way you remove some complexity of just adding steps in your constructor to something more abstract and can contain the logic.

public class Complex
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }

public double Height { get; set; }
public double Width { get; set; }

public string Foreground { get; set; }
public string Background { get; set; }

public Complex(ComplexBuildHelper buildHelper)
{
buildHelper.Construct(this);
}

}

public class ComplexBuildHelper
{
public void Construct(Complex reference)
{
BuildPosition(reference);
BuildDimension(reference);
BuildCharacteristics(reference);
}

private void BuildPosition(Complex reference)
{
reference.X = 1.456;
reference.Y = 1.234;
reference.Z = 1.789;
}

private void BuildDimension(Complex reference)
{
reference.Height = 10.12;
reference.Width = 10.14;
}

private void BuildCharacteristics(Complex reference)
{
reference.Foreground = "#FFF";
reference.Background = "#FA1";
}
}