private static Matcher<T> EqualTo<T>(T item)
{
return new IsEqual<T>(item);
}
How do I modify the above method definition such that the following are valid/allowed.
EqualTo("abc");
EqualTo(4);
EqualTo(null); // doesn't compile. EqualTo<string>(null) does
Trying to port some Java code where null seems to be acceptable value for a T parameter.
Update
Thanks: for all the answers - especially Eamon and Jason. I didn't want the method calls to bother with type-inference. The following overload fixed it.
private static Matcher<object> EqualTo(object item)
{
return EqualTo<object>(item);
}
Actually the above question was a part of a larger puzzle. The end goal was for the following to work.
this.AssertThat(null, EqualTo(null));
this.AssertThat(null, Not(EqualTo("hi")));
this.AssertThat("hi", Not(EqualTo(null)));
Applied the same fix.. RFC. (Ignore the ugly extension method part - that's another problem. Wanted to have these methods in all test-fixtures without inheritance.)
public static void AssertThat<T>(this object testFixture, object actual, Matcher<T> matcher, string message = "")
{
AssertThat(anyObject, (T)actual, matcher, message);
}
public static void AssertThat<T, TSuper>(this object testFixture, T actual, Matcher<TSuper> matcher, string message = "") where T : TSuper
{
... check and assert
Consider the following method:
public bool IsNullString<T>(T item) {
return typeof(T) == typeof(string) && item == null;
}
Yes, this is a pathetically stupid method and using generics is pointless here, but you'll see the point in a moment.
Now consider
bool first = IsNullString<string>(null);
bool second = IsNullString<Foo>(null);
bool third = IsNullString(null);
In the first and second, the compiler can clearly distinguish the type of T (no inference is needed). In the third, how the compiler infer what T is? In particular, it can't distinguish between T == string and T == Foo, or any other type for that matter. Therefore, the compiler has to give you a compile-time error.
If you want to get around this, you either need to cast null
EqualTo((object)null);
or explicitly state the type
EqualTo<object>(null)
or define an overload
private static Matcher<object> EqualTo(object item) {
return new IsEqual<object>(item);
}
Not possible without explicitly specifying a T or doing a cast. Generics are compile time constructs and as such if the compiler can't figure out the type at compile time, then it won't compile (as you're seeing).
Since you can't do exactly what you are wanting to do, how about defining an EqualTo(object) overloaded method? That should allow your required syntax.
You may work around this limitation by using the following syntax:
EqualTo("abc");
EqualTo(4);
EqualTo(default(object));
//equivalently:
EqualTo((object)null);
default(T) is the value a field of type T has if not set. For reference types, it's null, for value types it's essentially memory filled with zero bytes (...which may mean different things for different types, but generally means some version of zero).
I try to avoid the null everywhere in my code nowadays. It hampers type inference elsewhere too, such as with the var declared field and in a ternary operator. For example, myArray==null ? default(int?) : myArray.Length is OK, but myArray==null ? null : myArray.Length won't compile.
Maybe implementing a non-generic EqualTo, which takes an Object as the argument type, would solve the issue of rewriting those code lines.
Related
Consider the following code:
static void Main()
{
dynamic a = 1;
int b = OneMethod(a);
}
private static string OneMethod(int number)
{
return "";
}
Please notice that type of b and return type of OneMethod does not match. Nevertheless it builds and throws the exception at runtime. My question is that why does the compiler let this? Or what is the philosophy behind this?
The reason behind this may be Compiler does not know which OneMethod would be called, because a is dynamic. But why it cannot see that there is only one OneMethod. There will surely be an exception at runtime.
Any expression that has an operand of type dynamic will have a type of dynamic itself.
Thus your expression OneMethod(a) returns an object that's typed dynamically
so the first part of your code is equivalent to
static void Main()
{
dynamic a = 1;
dynamic temp = OneMethod(a);
int b = temp;
}
one way of argue why this is sensible even in your case depends on whether or not you think the compiler should change behavior for that particular line depending when you add the below method
private static T OneMethod<T>(T number)
Now the compiler won't know the type returned until runtime. It won't even know which method is called. The generic or the non generic. Wouldn't you be surprised if it in the first case marked the assignment as a compile error and then by adding a completely different method it got moved to a runtime error?
I have a method that looks like this (assume that I have the necessary method GetMySerializedDataArry() and my serializer JsonSerializer):
public static List<T> GetMyListOfData<T>()
{
var msgList = new List<T>();
foreach (string s in GetMySerializedDataArray())
{
msgList.Add(JsonSerializer.Deserialize<T>(s));
}
return msgList;
}
This works fine and as expected.
However, I want to use the same method to optionally, if and only if the generic type is specified as string, return the data unserialized like this (which does not compile and has syntax problems):
public static List<T> GetMyListOfData<T>(bool leaveSerialized)
{
if (typeof (T) != typeof(string) && leaveSerialized)
{
throw new ArgumentException("Parameter must be false when generic type is not List<string>", "leaveSerialized");
}
var msgList = new List<T>();
foreach (string s in GetMySerializedDataArray())
{
if (leaveSerialized)
{
// Casting does not work: "Cannot cast expression of type 'System.Collections.Generic.List<T>' to type 'List<string>'"
// I've tried various permutations of "is" and "as"... but they don't work with generic types
// But I know in this case that I DO have a list of strings..... just the compiler doesn't.
// How do I assure the compiler?
((List<string>)msgList).Add(s);
}
else
{
msgList.Add(JsonSerializer.Deserialize<T>(s));
}
}
return msgList;
}
My questions are in the inline comment.... basically though the compiler clearly doesn't like the cast of generic to non-generic, it won't let me use permutations of "is" and "are" operators either, I know I actually have the correct string in this case.... how to assure the compiler it is OK?
Many thanks in advance.
EDIT: SOLUTION
Thanks to Lee and Lorentz, both. I will be creating two public methods, but implementing the code in a private method with the admittedly icky decision tree about whether to leave serialization. My reason is that my real-world method is far more complex than what I posed here to SO, and I don't want to duplicate those business rules.
FINAL EDIT: CHANGED SOLUTION
Although both answers were very helpful, I have now been able to detangle business rules, and as a result the "correct" answer for me is now the first -- two different methods. Thanks again to all.
You should not return a list of strings as a list of T. I would suggest that you use two separate methods and skip the parameter:
public static List<T> GetMyListOfData<T>()
public static List<string> GetSerializedMyListOfData()
The advantages of this approach is
It's more readable (imo) GetSerializedMyListOfData() vs GetMyListOfData<string>(true)
You also know the intent of the caller at compile time and don't have to throw an exception when the type argument don't match the intent to leave the data serialized
You can cast to object first:
((List<string>)(object)msgList).Add(s);
however a cleaner solution could be to create another method for dealing with strings, this would also allow you to remove the leaveSerialized parameter.
I have a query about type of null.
I have a small program can anyone tell me about this.
public class TestApplication
{
public void ShowText(object ob)
{
Console.Write("Inside object");
}
public void ShowText(string str)
{
Console.Write("Inside string");
}
public void ShowText(int i)
{
Console.Write("Inside int.");
}
public void ShowText(char c)
{
Console.Write("Inside Character");
}
static void Main(string[] args)
{
new TestApplication().ShowText(null);
Console.Read();
}
}
Why it call the string function.
Is it means the type of null is string.
It might look a foolish conclusion but I am not able to find the region why it is calling the function of string.
Your question about the type of the null literal is answered here: What is the type of null literal?
But that doesn't really matter when talking about overload resolution. The actual null value itself will automatically be converted to whatever type it ends up as.
As for why the string overload is called:
You can't pass null as int and char parameters as they're value types, so those two overloads are out. (They could have been candidates had you made them nullable int? and char? types, but I won't go into that.)
Between the two other overloads taking reference types, string is a more specific type than object. That is, it derives from (and is therefore implicitly convertible to) object. Further, from the following section in the C# language spec (emphasis mine):
7.5.3.5 Better conversion target
Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
...
Thus, the string overload is chosen as the best fit.
null can fit to any reference-type. and hence is a very good example for polymorphism.
lets say you have a Vehicle class. you create three more class Two-Wheeler, Three-Wheeler, Four-Wheeler.
if latter 3 class extends Vehicle class; it is called Vehicle is specified into those three categories.
So, given a value, say car, more specific fit to this value is Four-Wheeler.
Similar is the case with null. it can fit to either Object OR String; but more specific match is String.
Lets see how compiler thinks (specific to your code only) when it sees a call to ShowText(null) method
Find ShowText method.
Oh, I've found 4, methods, which one to call?!!
Lets see what argument is passed, hmm .. it's null.
Find ShowText method which has reference type as argument. all overloads with primitive arguments are ignored.
Oh No ... i can match it to eithe string OR object.
Which is more specific. i.e which comes first in inheritance hierarchy from below.
Hurray .. found it .. it's string .. lets call it.
And, for an exercise if you want to undestand that what will happen if compiler finds at step 6 mor than one matches ... define a ShowText(string[] vals) and see yourself.
This is an example of the overload resolution in C#, it does not prove that the type of the null is string.
null is a special value that is included in the domain of any reference type, it basically determines that there is not a valid reference. As such, it can be a string, an int?, an object etc, etc.
You can even cast null to any reference type, to get a "correctly" typed null, e.g. you must cast null if it's used as a value in a ? operator
int? value = (i > 0) ? i : null; // does not compile
int? value = (i > 0) ? i : (int?)null; //works
From the docs:
The as operator is like a cast except that it yields null on conversion failure instead of raising an exception. More formally, an expression of the form:
expression as type
is equivalent to:
expression is type ? (type)expression : (type) null
except that expression is evaluated only once.
So why wouldn't you choose to either do it one way or the other. Why have two systems of casting?
They aren't two system of casting. The two have similar actions but very different meanings. An "as" means "I think this object might actually be of this other type; give me null if it isn't." A cast means one of two things:
I know for sure that this object actually is of this other type. Make it so, and if I'm wrong, crash the program.
I know for sure that this object is not of this other type, but that there is a well-known way of converting the value of the current type to the desired type. (For example, casting int to short.) Make it so, and if the conversion doesn't actually work, crash the program.
See my article on the subject for more details.
https://ericlippert.com/2009/10/08/whats-the-difference-between-as-and-cast-operators/
Efficiency and Performance
Part of performing a cast is some integrated type-checking; so prefixing the actual cast with an explicit type-check is redundant (the type-check occurs twice). Using the as keyword ensures only one type-check will be performed. You might think "but it has to do a null check instead of a second type-check", but null-checking is very efficient and performant compared to type-checking.
if (x is SomeType )
{
SomeType y = (SomeType )x;
// Do something
}
makes 2x checks, whereas
SomeType y = x as SomeType;
if (y != null)
{
// Do something
}
makes 1x -- the null check is very cheap compared to a type-check.
Because sometimes you want things to fail if you can't cast like you expect, and other times you don't care and just want to discard a given object if it can't cast.
It's basically a faster version of a regular cast wrapped in a try block; but As is far more readable and also saves typing.
It allows fast checks without try/cast overhead, which may be needed in some cases to handle message based inheritance trees.
I use it quite a lot (get in a message, react to specific subtypes). Try/cast wouuld be significantly slower (many try/catch frames on every message going through) - and we talk of handling 200.000 messages per second here.
Let me give you real world scenarios of where you would use both.
public class Foo
{
private int m_Member;
public override bool Equals(object obj)
{
// We use 'as' because we are not certain of the type.
var that = obj as Foo;
if (that != null)
{
return this.m_Member == that.m_Member;
}
return false;
}
}
And...
public class Program
{
public static void Main()
{
var form = new Form();
form.Load += Form_Load;
Application.Run(form);
}
private static void Form_Load(object sender, EventArgs args)
{
// We use an explicit cast here because we are certain of the type
// and we want an exception to be thrown if someone attempts to use
// this method in context where sender is not a Form.
var form = (Form)sender;
}
}
I generally choose one or the other based on the semantics of the code.
For example, if you have an object that you know that it must be an string then use (string) because this expresses that the person writing the code is sure that the object is a string and if it's not than we already have bigger problems than the runtime cast exception that will be thrown.
Use as if you are not sure that the object is of a specific type but want to have logic for when it is. You could use the is operator followed by a cast, but the as operator is more efficient.
Maybe examples will help:
// Regular casting
Class1 x = new Class1();
Class2 y = (Class2)x; // Throws exception if x doesn't implement or derive from Class2
// Casting with as
Class2 y = x as Class2; // Sets y to null if it can't be casted. Does not work with int to short, for example.
if (y != null)
{
// We can use y
}
// Casting but checking before.
// Only works when boxing/unboxing or casting to base classes/interfaces
if (x is Class2)
{
y = (Class2)x; // Won't fail since we already checked it
// Use y
}
// Casting with try/catch
// Works with int to short, for example. Same as "as"
try
{
y = (Class2)x;
// Use y
}
catch (InvalidCastException ex)
{
// Failed cast
}
public static T IsNull<T>(object value, T defaultValue)
{
return ((Object.Equals(value,null)) | (Object.Equals(value,DBNull.Value)) ?
defaultValue : (T)value);
}
public static T IsNull<T>(object value) where T :new()
{
T defaultvalue = new T();
return IsNull(value, defaultvalue);
}
Have tested, and can use against data objects, classes and variables.
Just want to know if there is better way to go about this.
It looks like you're trying to duplicate the null coalesce operator:
var foo = myPossiblyNullValue ?? defaultValue;
First off, the method name is wrong. You imply that the result of the function is a boolean that is true exactly if the given value is null. In fact, that’s not the case. GetValueOrDefault might be a better name.
Secondly, you’re merely replicating the behaviour of the null coalesce operator, as mentioned by others.
Thirdly, your conditional is odd:
Object.Equals(value,null)) | (Object.Equals(value,DBNull.Value)
Why Object.Equals instead of ==? Better yet, use Object.ReferenceEquals since that makes it clear that you’re interested in reference equality. Also, you’re using the bitwise-or operator (|) which is semantically wrong in this context, although it happens to yield the right value. You want the boolean-or operator ||. (Also, inconsistency: why do you sometimes write object and other times Object?)
Finally, using type object instead of a generic type isn’t necessarily a good solution. It would be better to create overloads for generic reference and value types: this avoids boxing in the value types. It also means that you don’t have to specify the type explicitly in your second overload since it can be deduced from the method argument.
public static bool IsNull<T>(object value)
{
return object == default(T);
}
[Edited]
The following (non-generic) should work.
public static bool IsNull(object value)
{
return value == null;
}
Any value type will get boxed (i.e. non-null). Ref types will just be passed by pointer.