General Generics c# - c#

So I have this test program:
namespace ConsoleApplication1TEST{
class Program
{
static void Main(string[] args)
{
new derp<int,int>(5,4);
}
}
class derp<T,V>
{
public T top;
public V vop;
public derp(T to, V vo)
{
top = to;
vop = vo;
top.ToString();
}
}
}
top.ToString is allowed. As are GetHashCode, GetType, and Equals. However, ToUpper is not allowed, and neither are other string-specific methods. Can this be changed?
When I place a method that is not allowed, this is the error I get:
Error 1 'ConnectionServiceT' does not contain a definition for
'connect' and no extension method 'connect' accepting a first argument
of type 'ConnectionServiceT' could be found (are you missing a using
directive or an assembly reference?)

top.ToString is allowed. GetHashCode, GetType, Equals is also allowed.
However, ToUpper is not allowed, and other string-specific methods are not allowed. Can this be changed?
That's perfectly normal. The compiler knows nothing about the actual type of T, so it can't assume that it has a ToUpper method. However, since all types (except pointers) inherit from Object, calling methods of the Object class is allowed.
Now, if there was a constraint on T to force it to inherit a type that has a ToUpper method, your code would work:
class derp<T,V> where T : String
It's a bad example, because String is sealed, so this code wouldn't compile, but it's just to illustrate the idea.
Anyway, if you want to be able to call the String.ToUpper method on top, then the type of top cannot be generic: it has to be String.
To learn more about generic constraints, see MSDN: http://msdn.microsoft.com/en-us/library/d5x73970.aspx

It is reasonable that the method ToUpper() is not allowed, since this is a method specific for string types. If your type isn't a string then you can't use the ToUpper() method, because this method is specific to string types.
On the other hand, since all types inherrit the object type, they inherit it's methods, which are ToString(), GetHashCode(), GetType() and Equals().
This is a good link regarding the inheritance in C#, in where you can see more thoroughly what I am talking about.
Also here is stated that:
In the unified type system of C#, all types, predefined and user-defined, reference types and value types, inherit directly or indirectly from Object.

.ToString() works on every type. If the type is not a string the type's name will be returned.
.ToUpper() is a string specific, won't work on types other than string.

Can this be changed?
You don't know what T and V are, so the only assumption the compiler can make is that they inherit from object, which is why ToString, GetHashCode, GetType, and Equals are allowed (since they're methods on object which every class inherits from).
If ConnectionServiceT (and other similar classes) inherit from a base class you can constrain T and V to be subclasses of a given type:
class derp<T,V> where T:BaseService
where V:MyOtherClass
{
public T top;
public V vop;
public derp(T to, V vo)
{
top = to;
vop = vo;
top.ToString();
}
}
Then you can call methods specific to BaseService on instances of T (since you know that T must derive from BaseService.
But you can't constrain to string because it's sealed - the only possible class would be derp<string, string> so there's no reason to use generics.

It is a good thing you cant use ToUpper(). You are sending in integers, those certainly do not have a ToUpper method. ToUpper is a method that belongs to string objects. You could do this:
string myUpperCaseString = top.ToString().ToUpper();
//or
if(top.GetType() == typeof(string)
{
string myUpperCaseString = (top as string).ToUpper();
}
What you may have been mistaken about, is that ToString() does not change the string... it instead returns a new string representation of that object, you then have to store this object somewhere. Above I stored it in a variable called myUpperCaseString with the type of string.
ToString, GetHashCode, GetType are all methods that belong to the object class and anything that inherits from it.

Related

How is the default ToString() method of Object class implemented?

Imagine you have two of this simple classes:
class Class1
{
}
class Class2
{
}
We all know that all classes by default inherits from object class.
So imagine this code:
int num = new Random().Next(1, 3);
object obj = num == 1 ? new Class1() : new Class2();
Console.WriteLine(obj.ToString());
So based on random number the output will be namespace.Class2 or namespace.Class1.
And note that I'm assigning these classes to object class.
My questions are:
How ToString() of objectclass can find out the original derived class type? (namespace.Class2 or namespace.Class1)
Can we use the result of ToString() method to cast the type successfuly? If yes, How?
How ToString() of objectclass can find out the original derived class type? (namespace.Class2 or namespace.Class1)
When casting you do not change the object itself, only the reference to the object. So ToString() will still check the actual object type (and not the reference type) to find the correct method to call.
All objects have a header that contain type information a bunch of other stuff used by the runtime. Note that value types like int and struct lack such a header so will be more compact. However, these value types will be boxed if cast to object, and that will incur the object overhead, so it is best avoided where possible.
Can we use the result of ToString() method to cast the type successfuly? If yes, How?
There is really no point. If you want to do a safe cast just do
if(obj is Class1 myClass1Reference){
...
}
You can also use dynamic to essentially turn of type-checking, resulting in runtime errors instead of compile-time errors, but that is rarely a good idea unless you are working with something like COM.

How to tell a constructor it should only use primitive types

I created an Class which is only able to handle primitive (or ICloneable) Types
I want to know if it's possible to say something like:
public myobject(primitiv original){...}
or do I really need to create a constructor for each primitive type like:
public myobject(int original){...}
public myobject(bool original){...}
...
What I am trying to achieve is to create an object with 3 public properties Value, Original and IsDirty.
The Value will be an deep Clone of Original so the Original needs to be primitve or ICloneable
Primitive types in C# are defined as structs (implemented generally as ValueType in the .NET CLR). I believe you have two options:
As has been said already: Receive any type, check it against every acceptable type, throw an exception if it doesn't match.
Make your class generic, make the constructor generic with a constraint of where T : struct (with T being the type parameter). This will catch all structs, not just the primitive types, but I think that's the best you can hope for without manual checking and with compile-time checking. You can mix this constraint with other ones, of course.
And you can combine the two options above to have some of the checking be done at compile-time and some of it be done at run-time.
If you want to do that to force whomever is using your API to use such types (through compile time errors should they use the wrong types), I'm afraid it can't be done.
You could, however, receive an object in the constructor, evaluate its type, and throw an ArgumentException in case the parameter is neither one of the "primitive" types nor implements ICloneable.
Edit: This might be useful. You can determine whether a variable belongs to a primitive type with the following code:
Type t = foo.GetType();
t.IsPrimitive; // so you don't have to do an evaluation for each primitive type.
It is not exactly what you asked, but you can have 2 constructors, one for structs and one for ICloneable:
public myobject(System.ValueType original){...}
public myobject(ICloneable original){...}
How about generics instead of reflection?
public class MyObject<T>
where T: IComparable
{
public MyObject(T original)
{
// do runtime check
}
}
var c1 = new MyObject<int>(1);
// or
var c2 = new MyObject<Int32>(2);

c# Generics: Passing List<string> to a method that expects a List<T>

I've had my first foray into generics, and understand them a little bit. I have a method intended to accept two lists of any object, match them various ways and return the matched/unmatched objects (the stuff inside the method probably isn't key here). The purpose is to accept any kind of object, be it customers, or whatever. However, I've hit a snag with getting it to accept 'string', I'm guessing because it's not initialised with the new() keyword and isn't like a normal instanced class.
So, I have a method declaration like so:
public static compareResult<T> stepCompare<T>(List<T> leftList, List<T> rightList, Comparison<T> IDComparer = null, Comparison<T> lowLevelComparer = null, bool confirmUniqueness = true) where T : IComparable, new()
Admittedly, adding the where clause at the end was in response to an error "cannot create an instance of the variable type 'T' because it does not have the new() constraint". This appeared against a line in the method saying
T lastItem = new T();
However, now if I try to pass it two Lists<string>, it says "'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'MF.Comparers.stepCompare<T>(System.Collections.Generic.List<T>, System.Collections.Generic.List<T>, System.Comparison<T>, System.Comparison<T>, bool)'...
Any way to let this method accept lists whether they be of string or other classes? Or a shortcut to put lists of string into a type that will be accepted?
You can't make string satisfy the new() constraint, no. While string is a normal class, and instances can be created using constructors in a perfectly normal way, it doesn't have a parameterless constructor.
The best approach really depends on why you had that line of code including lastItem. If you just want some default value, then default(T) is probably the best approach.
If you really do want to create a new instance of T, then you should probably accept a Func<T> in the method's parameter list, as a way of creating a default value on demand. Alternatively, if you're happy using a particular single value as the default, you could just add a parameter of type T. It's hard to say without seeing the rest of your code.
If you want any object, you probably have to live without the new T(). You could do the same with a combination of reflection, special-cases (for string etc), and Activator.CreateInstance<T>() - however, IMO you should limit yourself (in this case) to default(T), which will be null for reference types (including string) and nullable value-types, and all-zeros for non-nullable value-types. You should also probably use a bool or similar to make sure you don't actually use that value, except to satisfy definite assignment rules for the compiler.

C# question on what this code means

I am learning c# code from one of the applications that I run SQL queries from.
I am wondering what the following code does in layman's terms:
return typeof(ViewModelBase<T>).GetProperty(propertyName) != null;
This is in a function that returns a boolean and a string is passed into it.
ViewModelBase<T> is an abstract class. Can someone also explain what the <T> does in this? I have ideas on these but I'm not sure what exactly is true.
Thanks!
The code returns true if the type has the property, and false if it doesn't.
This code will be written inside of a generic class, with a type parameter of T. In generics, each time a "hard" type is used with the generic class, the compiler creates a brand new concrete type. So for example, if there was code in your project that was using ViewModelBase<int>, ViewModelBase<string>, and ViewModelBase<MyType>, there would be three concrete types created in the final assembly by the compiler.
Each of these three hypothetical types would have properties and methods. The code shown above would (for all intents and purposes) be duplicated three times, with the type parameter "T" substituted with int, string and MyType in each of the three cases.
GetProperty() would then check to see if the concrete types had the property given in the "propertyName" variable, and return true or false accordingly.
That tells you whether or not the class type ViewModelBase<T>, based on the given type of T, has a public property with the same name as the value of propertyName.
Type.GetProperty() returns a PropertyInfo object if there's such a property; null otherwise. Hence the boolean comparison against null.
The code piece that you have there is part of a generic type, having a type argument T. Now, we don't see the full method, but I can imagine it looks something like so:
public static bool T HasProperty<T>(string propertyName)
{
return typeof(ViewModelBase<T>).GetProperty(propertyName) != null;
}
Let's say you have a class Customer:
class Customer
{
// implementation of class Customer goes here
}
Then you could call the HasProperty method like this:
bool itsThere = HasProperty<Customer>("SomePropertyName");
This means that the HasProperty method will return true if ViewModelBase<Customer> has a property called SomePropertyName, otherwise false.
This checks whether ViewModelBase<T> has a property with a name equal to propertyName.

Why it isn't possible to declare a method parameter as var type

I wonder why it is not possible a method parameter as var type like
private void myMethod(var myValue) {
// do something
}
You can only use var for variables inside the method body. Also the variable must be assigned at declaration and it must be possible to deduce the type unambiguously from the expression on the right-hand side.
In all other places you must specify a type, even if a type could in theory be deduced.
The reason is due to the way that the compiler is designed. A simplified description is that it first parses everything except method bodies and then makes a full analysis of the static types of every class, member, etc. It then uses this information when parsing the method bodies, and in particular for deducing the type of local variables declared as var. If var were allowed anywhere then it would require a large change to the way the compiler works.
You can read Eric Lippert's article on this subject for more details:
Why no var on fields?
Because the compiler determines the actual type by looking at the right hand side of the assignment. For example, here it is determined to be a string:
var s = "hello";
Here it is determined to be Foo:
var foo = new Foo();
In method arguments, there is no "right hand side of the assignment", so you can't use var.
See the posting by Eric Lippert about why var is not allowed on fields, which also contains the explanation why it doesn't work in method signatures:
Let me give you a quick oversimplification of how the C# compiler works. First we run through every source file and do a "top level only" parse. That is, we identify every namespace, class, struct, enum, interface, and delegate type declaration at all levels of nesting. We parse all field declarations, method declarations, and so on. In fact, we parse everything except method bodies; those, we skip and come back to them later.
[...]
if we have "var" fields then the type of the field cannot be determined until the expression is analyzed, and that happens after we already need to know the type of the field.
Please see Juliet's answer for a better answer to this question.
Because it was too hard to add full type inference to C#.
Other languages such as Haskell and ML can automatically infer the most general type without you having to declare it.
The other answers state that it's "impossible" for the compiler to infer the type of var but actually it is possible in principle. For example:
abstract void anotherMethod(double z, double w);
void myMethod<T>(T arg)
{
anotherMethod(arg, 2.0); // Now a compiler could in principle infer that arg must be of type double (but the actual C# compiler can't)
}
Have "var" method parameters is in principle the same thing as generic methods:
void myMethod<T>(T arg)
{
....
}
It is unfortunate that you can't just use the same syntax for both but this is probably due to the fact that that C#'s type inference was added only later.
In general, subtle changes in the language syntax and semantics can turn a "deterministic" type inference algorithm into an undecidable one.
ML, Haskell, Scala, F#, SML, and other languages can easily figure out the type from equivalent expressions in their own language, mainly because they were designed with type-inference in mind from the very start. C# wasn't, its type-inference was tacked on as a post-hoc solution to the problem of accessing anonymous types.
I speculate that true Hindley-Milner type-inference was never implemented for C# because its complicated to deduce types in a language so dependent on classes and inheritance. Let's say I have the following classes:
class Base { public void Print() { ... } }
class Derived1 : Base { }
class Derived2 : Base { }
And now I have this method:
var create() { return new Derived1(); }
What's the return type here? Is it Derived1, or should it be Base? For that matter, should it be object?
Ok, now lets say I have this method:
void doStuff(var someBase) { someBase.Print(); }
void Main()
{
doStuff(new Derived1());
doStuff(new Derived2()); // <-- type error or not?
}
The first call, doStuff(new Derived1()), presumably forces doStuff to the type doStuff(Derived1 someBase). Let's assume for now that we infer a concrete type instead of a generic type T.
What about the second call, doStuff(new Derived1())? Is it a type error, or do we generalize to doStuff<T>(T somebase) where T : Base instead? What if we made the same call in a separate, unreferenced assembly -- the type inference algorithm would have no idea whether to use the narrow type or the more genenarlized type. So we'd end up with two different type signatures based on whether method calls originate from inside the assembly or a foreign assembly.
You can't generalize wider types based on usage of the function. You basically need to settle on a single concrete type as soon as you know which concrete type is being pass in. So in the example code above, unless you explicitly cast up to the Base type, doStuff is constrained to accept types of Derived1 and the second call is a type error.
Now the trick here is settling on a type. What happens here:
class Whatever
{
void Foo() { DoStuff(new Derived1()); }
void Bar() { DoStuff(new Derived2()); }
void DoStuff(var x) { ... }
}
What's the type of DoStuff? For that matter, we know based on the above that one of the Foo or Bar methods contain a type error, but can you tell from looking which has the error?
Its not possible to resolve the type without changing the semantics of C#. In C#, order of method declaration has no impact on compilation (or at least it shouldn't ;) ). You might say instead that the method declared first (in this case, the Foo method) determines the type, so Bar has an error.
This works, but it also changes the semantics of C#: changes in method order will change the compiled type of the method.
But let's say we went further:
// Whatever.cs
class Whatever
{
public void DoStuff(var x);
}
// Foo.cs
class Foo
{
public Foo() { new Whatever().DoStuff(new Derived1()); }
}
// Bar.cs
class Bar
{
public Bar() { new Whatever().DoStuff(new Derived2()); }
}
Now the methods is being invoked from different files. What's the type? Its not possible to decide without imposing some rules on compilation order: if Foo.cs gets compiled before Bar.cs, the type is determined by Foo.cs.
While we can impose those sorts of rules on C# to make type inference work, it would drastically change the semantics of the language.
By contrast, ML, Haskell, F#, and SML support type inference so well because they have these sorts of restrictions: you can't call methods before they're declared, the first method call to inferred functions determines the type, compilation order has an impact on type inference, etc.
The "var" keyword is used in C# and VB.NET for type inference - you basically tell the C# compiler: "you figure out what the type is".
"var" is still strongly typed - you're just too lazy yourself to write out the type and let the compiler figure it out - based on the data type of the right-hand side of the assignment.
Here, in a method parameter, the compiler has no way of figuring out what you really meant. How? What type did you really mean? There's no way for the compiler to infer the type from the method definition - therefore it's not a valid statement.
Because c# is type safe and strong type language. At any place of your program compiler always knows the type of argument you are using. var keyword was just introduced to have variables of anonymus types.
Check dynamic in C# 4
Type inference is type inference, either in local expressions or global / interprocedural. So it isn't about "not having a right hand side", because in compiler theory, a procedure call is a form of "right hand side".
C# could do this if the compiler did global type inference, but it does not.
You can use "object" if you want a parameter that accepts anything, but then you need to deal with the runtime conversion and potential exceptions yourself.
"var" in C# isn't a runtime type binding, it is a compile time feature that ends up with a very specific type, but C# type inference is limited in scope.

Categories

Resources