Did you ever typed a code like this and thought “there should be a is_not operator”?

if (!(config.LogSection.LogTarget is FileSystemTarget))
{
// Do something
}


I know I’m not the only one, and the common solution is to define an extension method:

public static bool IsNot<T>(this object myObject)
{
return !(myObject is T);
}

// Usage:
if (child.IsNot<IContainer>())
{
// child is not an IContainer
}


(Taken from this StackOverflow topic) That’s it, case closed, right? Not really, as I discovered shortly after. Here are two versions of the same code side by side:

if (!(config.LogSection is FileSystemLogTarget))
{
// Do something
}

if (config.LogSection.IsNot<FileSystemLogTarget>())
{
// Do something
}


Both compile but the first one (the original is not) produces a warning: The given expression is never of the provided type

A-ha, we’ve avoided a subtle bug and in a world full of wrappers, adapters, converters and facades it’s a useful behaviour.

So, how do we mimik it? Ideally, I would write:

public static bool IsNot<T, S>(this T _this) where S : T
{
return !(_this is S);
}


Unfortunately, this doesn’t quite work.

if (config.LogSection.LogTarget.IsNot<FileSystemLogTarget>())
{
// Do something
}


This produces an error: Using the generic method ‘GenericExtensions.Extensions.IsNot<T,S>(T)’ requires 2 type arguments This is unfortunate since it’s obvious that T can be infered from usage. You can resolve the issue by specifing types explicitly:

if (config.LogSection.LogTarget.IsNot<LogTarget, FileSystemLogTarget>())
{
// Do something
}


But this defeats the purpose as it makes the code even less readable then before.

After giving it some thought I came up with the following trick:

public static Identity<T> Is<T>(this T _this) where T : class
{
return new Identity<T>
{
Value = _this
};
}

public class Identity<T> where T : class
{
public T Value { get; set; }

public bool Not<S>() where S : T
{
return !(Value is S);
}
}

// Usage:
if (config.LogSection.LogTarget.Is().Not<FileSystemLogTarget>())
{
// Do something
}


And if you try to compile:

if (config.LogSection.Is().Not<FileSystemLogTarget>())
{
// Do something
}


You will get a compile-time error: The type ‘GenericExtensions.Tests.FileSystemLogTarget’ cannot be used as type parameter ‘S’ in the generic type or method ‘GenericExtensions.Identity<T>.Not<S>()’. There is no implicit reference conversion from ‘FileSystemLogTarget’ to ‘ConfigSection’. This clearly conveys the message that you are trying to convert apples to oranges.

The idea is that if you want more then one generic type in an extension method, you can capture the original type T in a class, and then write regular generic methods and use the original type as a constraint.

I assume I’m not the only to come up with this solution, and it’s just not elegant enough to be popular. But it’s always nice to solve a problem in a neat type-safe fassion.

Source code is available here

It includes couple more goodies, like:

if (message.Is().NotNull())
{
message.If()
.Is<UrgentMessage>(OnUrgentMessage)
.Is<InfoMessage>(Console.WriteLine)
.Else(() => Console.WriteLine("Unknow message!"));
}


.. partially inspired by this excelent blog post