Implicit typing of arrays that implement interfaces - c#

I was under the impression that the C# compiler will implicitly type an array based off a type that they can all be implicitly converted to.
The compiler generates
No best type found for implicitly-typed array
public interface ISomething {}
public interface ISomething2 {}
public interface ISomething3 {}
public class Foo : ISomething { }
public class Bar : ISomething, ISomething2 { }
public class Car : ISomething, ISomething3 { }
void Main()
{
var obj1 = new Foo();
var obj2 = new Bar();
var obj3 = new Car();
var objects= new [] { obj1, obj2, obj3 };
}
I know that the way to correct this is to declare the type like:
new ISomething [] { obj1, ...}
But I'm after an under the covers type help here.

The C# compiler considers the set of types of all the specified elements. It does not consider common base types etc.
You could cast one of the expressions:
var objects= new [] { obj1, obj2, (ISomething) obj3 };
... but personally I'd just use the explicit form:
var objects= new ISomething[] { obj1, obj2, obj3 };
Alternatively, if you explicitly declared any or all of obj1, obj2 and obj3 as type ISomething, that would work fine too without changing the array initialization expression.
From the C# 3 spec, section 7.5.10.4:
An array creation expression of the
third form is referred to as an
implicitly typed array creation
expression. It is similar to the
second form, except that the element
type of the array is not explicitly
given, but determined as the best
common type (§7.4.2.13) of the set of
expressions in the array initializer.
Section 7.4.2.13 looks like this:
In some cases, a common type needs to
be inferred for a set of expressions.
In particular, the element types of
implicitly typed arrays and the return
types of anonymous functions with
block bodies are found in this way.
Intuitively, given a set of
expressions E1…Em this inference
should be equivalent to calling a
method
Tr M<X>(X x1 … X xm)
with the Ei as arguments. More
precisely, the inference starts out
with an unfixed type variable X.
Output type inferences are then made
from each Ei with type X. Finally, X
is fixed and the resulting type S is
the resulting common type for the
expressions.

If the instances can all be cast to the type of any one instance, than that type will be used. It's not enough for all instances to have any type in common, or else the implicity array initialization would always succeed and often generate undesired new object[] arrays.

As a slight addition to the Skeet's reply:
You can either cast one of the array items to the type you need (interface in this case) or if you had just a single element of that type (not deriving but of a direct type). Such as
public static IWindsorInstaller[] MobileRestComponentInstallers
{
get
{
return new []
{
new RepositoryInstaller(),
new AppSettingsInstaller(),
// tens of other installers...
GetLoggerInstaller() // public IWindsorInstaller GetLoggerInstaller()...
};
}
}
this will work, but pls don't do that :) Just define the array type and change the new[] to new IWindsorinstaller[].
It's much more readable having the array type defined explicitly.

Do like this for Class object( UIViewController) initialization in var array:
var page1 = new Class1();
var page2 = new Class2();
var pages = new UIViewController[] { page1, page2 };
Note: here UIViewController can be any class

Related

C# Can you box and unbox generic classes?

You can box and unbox types like this:
List<object> items = new List<object>();
items.Add("hello");
items.Add(123);
Here, it doesn't matter what we put in, as long as it derives from object. So this works.
But is it possible to do it with generic classes?
Like this:
public class Foo<T>
{
public T MyItem;
}
static void Main()
{
List<Foo<object>> items = new List<Foo<object>>();
items.Add(new Foo<string>() { MyItem = "Hello" });
items.Add(new Foo<int>() { MyItem = 123 });
}
Here, it will give me an error despite string and int is type of object.
There is one easy solution that i have thought about, and that is by turning new Foo< string > into new Foo< object >, and then just put in string value in the object type like this:
items.Add(new Foo<object>() { MyItem = "Hello" });
But i'm in a situation where i cant do that.
So is there any solution to make this possible?
To attempt to make your code compile:
You would have to make the parameter T covariant which can only be done on interfaces and delegates. The other limiting factor when defining T as covariant is that T cannot be a value type.
Documentation - out (Generic Modifier) (C# Reference)
For generic type parameters, the out keyword specifies that the type parameter is covariant. You can use the out keyword in generic interfaces and delegates.
... Covariance and contravariance are supported for reference types, but they are not supported for value types.
The question about boxing/unboxing also does not apply in this situation with generics. Generics ensure there never is boxing or unboxing (by default) on the type parameters. There are plenty of good links in the comments, I recommend you read through them so you have a better understanding of 1) boxing/unboxing and 2) generics.
This is the closest you can get with your code
static void Main() {
List<IFoo<object>> items = new List<IFoo<object>>();
items.Add(new Foo<string>() { MyItem = "Hello" });
// not possible because int is a value type
// items.Add(new Foo<int>() { MyItem = 123 });
}
interface IFoo<out T>
{
T MyItem {get;}
}
class Foo<T> : IFoo<T>
{
public T MyItem {get;set;}
}
Given this class:
public class Foo<T>
{
public T MyItem { get; set; }
}
If you have a list of Foo<object> you can't add a Foo<int> to it.
If you could, then you could do this:
var myListOfFoos = new List<Foo<object>>();
myListOfFoos.Add(new Foo<int>());
Foo<object> firstFoo = myListOfFoos[0]; // this is the Foo<int> you added.
firstFoo.MyItem = "string!"; // How can you do this with a Foo<int>?
My eyes always glaze over from the words "covariant" and "contravariant." The compiler is always protecting you from a scenario like this. You just have to figure out what it's (correctly) protecting you from trying to do.

Passing generic into a class constructor list

I have a class that takes a generic as a parameter like this
public MyNewClass(string text, T myClass, int f, bool test = false)
The compiler is complaining about T myClass.
I know I can pass "defined" generic classes to a class constructor (such as List, Dictionary etc) and have seen that this can be done in C# as well, but can't find a reference to it.
You should declare the generic parameter, when you declare your class.
public class MyNewClass<T>
{
}
Then this parameter could be accessible from any of the class's methods. When you will create an instance of your MyNewClass, you should define also the type of T, for instance:
var instanceOfMyNewClass = new MyNewClass<className>(text, classIntance, f, true);
where classInstance is an instance of an object of type className.
A good introduction about generics is here.
I suspect that the issue you are facing is that the following does not compile
public class Foo<T>
{
public Foo(string s, T t) { }
}
var foo = new Foo("Hello", new Something());
The fix to this is to specify in the constructor.
var foo = new Foo<Something>("Hello", new Something());
However, this still seems a little strange given that normally, the C# compiler can infer the type of T.
The problem here is that the C# compiler is only allowed to infer generics on the first parameter of a method. So the following IS allowed.
public class Foo<T>
{
public Foo(T t, string s) { }
}
var foo = new Foo(new Something(), "Hello");

How does C# do runtime generics?

One thing that irritates me about Java is the awful implementation of compile-time translation of generic type arguments.
I can observe and understand that the C# implementation is far better, but I'm confused as to how it works.
Essentially, how can you say:
T t = new T()
If you don't know the type of T and therefore don't know the constructor argument requirements?
I can see
Class<T> cl = T.class
or
T[] tarr = new T[0]
but I don't see how you can really create a new instance of T if you don't know the requirements of constructing it?
You can only do new T(); if T is constrained to have a plain, parameterless public constructor, for instance:
public class Foo<T> where T : new() {
private myT = new T();
}
Additionally, there is no way to specify that any other sort of constructor exist. This is not possible:
// Doesn't work
public class Foo<T> where T : new(String, Int) {
private myT = new T("Foo", 5);
}
To your other points, this is how you get the type of T at runtime:
var tType = typeof(T);
and creating an array of T doesn't actually create any instances (unless T is a value type, in which case it creates the default value of that type):
// Space for 32 T's, but nothing in the array.
// If T is a value type, like an int for instance,
// each one would have the default value (0 for int, for example)
var arrayOfT = new T[32];
You cannot say new T() unless you constrain your generic type to have a parameterless constructor using the where T : new() constraint — see Constraints on Type Parameters.
And there are no “constructor argument requirements”, since the only supported constructor is the parameterless one. You cannot use, say, new T(false) — constraints of the form where T : new(bool) are not allowed.
Actually you ask the compiler to force T to have a parameterless constructor so he knows you can new T(). For example:
class Test<T>
{
T Create()
{
return new T();
}
}
It won't compile because the compiler can't be sure that T won't be an abstract class and that it'll have a default constructor. To make it works you have to add a constrain on the real type of T:
class Test<T> where T : new()
Now the compiler will force T to be a non abstract class with a default constructor. For example this code is not valid because the given type is abstract:
abstract class AnotherTest
{
public void Test()
{
Test<Derived> test = new Test<Derived>();
}
}
Again, if you try to use a class without default constructor the compiler will emit an error:
class AnotherTest
{
public AnotherTest(string someParameter)
{
}
public void Test()
{
Test<Derived> test = new Test<Derived>();
}
}
With an array it's a little bit different. Actually you simply ask the compiler to reserve the memory for a given number of slots, you do not allocate the memory for that objects (in case of reference types it'll simply put null in each slot).
References on MSDN
Introduction to generics
Generic type constrain
The new constrain
new T() is just a syntactical sugar for Activator.CreateInstance<T>()

Force type cast between classes of different namespaces

How Force type cast between classes of different namespaces.
Both namespaces have same class.
You can't cast an object to a type it is not. If it belongs to a different namespace then it is not the same class. You will have to create a converter:
public static Namespace1.SomeClass Convert(Namespace2.SomeClass someClass) {
Namespace1.SomeClass rtn = new Namespace1.SomeClass();
rtn.SomeProp = someClass.SomeProp;
rtn.SomeOtherProp = someClass.SomeOtherProp;
return rtn;
}
you could even use reflection to set all the properties on Namespace1.SomeClass that have the same name as Namespace2.SomeClass.
Also, if you own the code to one of the classes, you can check into overloading explicit and implicit on your class.
You can create generic Converter so you don't have to do this each time you need to cast a different type of objects,
T ConvertObject<T>(object M) where T : class
{
// Serialize the original object to json
// Desarialize the json object to the new type
var obj = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(M));
return obj;
}
// Test ObjectToCast is type Namespace1.Class, obj is Namespace2
Namespace2.Class obj = ConvertObject<Namespace2.Class>(ObjectToCast);
Assuming that both classes are the same this will work.
You can't cast from a Type to a different Type, even if the code of the class is exactly the same.
You can create a Converter capable to convert between the two types, or provide implicit/explicit casts inside both classes implementations or eventually you can try Automapper.
You need to qualify the type:
namespace Foo
{
class Bar {}
}
namespace Baz
{
class Bar {}
}
Foo.Bar x = new Foo.Bar();
Baz.Bar y = (Baz.Bar)x;
Of course, this will fail unless there is a conversion defined.
This is not possible. A type include its namespace as part of its full name.
Its like the town of Springfield: same name but from different states. They are all different.
A possible approach would be to overload the cast operator of one of the type so that they can be cast into another type. It won't be a real cast, as the result will be to create a new object with the same value.
public static explicit operator Massachusetts.Springfield(Illinois.Springfield town)
{
return new Massachusetts.Springfield(town); // or any other code to copy the fields from one type to the other
}
If both classes are serializable, you can serialize the first object to XML, change the "namespace" in the xml and deserialize it again.
The fact that the two classes have the same name doesn't mean anything to the compiler. You may have Foo.Orange and Bar.Orange, but to the compiler it may as well be Apple and Orange. To convert:
namespace Foo
{
public class Orange{}
public static explicit operator Foo.Orange(Bar.Orange) { // conversion code }
}
namespace Bar
{
public class Orange{}
public static explicit operator Bar.Orange(Foo.Orange) { // conversion code }
}
// somewhere else
Foo.Orange o = new Foo.Orange();
Bar.Orange bar = (Bar.Orange)o; // and vice-versa

Create hierarchical anonymous type

Is there any way to create anonymous type that references instances of itself?
var root = new { Name = "Root", Parent = ??? };
var child = new { Name = "Child", Parent = root };
var childOfChild = new { Name = "Grand child", Parent = child };
For example, we can reference delegate from itself:
Action run = null;
run = () => run();
Another example, we can create generic Stack of anonymous types:
static Stack<T> CreateStack<T>(params T[] values)
{
var stack = new Stack<T>();
foreach (var value in values)
stack.Add(value);
return stack;
}
Can you think of any ways to reference anonymous type from itself?
Anonymous types in C# are immutable. Therefore all of their field values must have been present before the creation of the object and will never change. And therefore it is impossible to have a directly circular referencing anonymous type in C#.
Anonymous types in VB are mutable; you could probably figure out some way to do it in VB.
There might be a way to make an anonymous type indirectly reference itself, by, say, containing a delegate that when invoked, returns the instance of the anonymous type. I don't see any way off the top of my head to easily do that, but I also don't see a proof that doing so is impossible. Give it some thought and see what you come up with!
I assume this question is for entertainment purposes only. If you want to make a circularly-referential object, please make a nominal type.
It seemed... that the C# compiler will simply refuses to infer the type recursively. Take this sample code for example:
(From #Eric: Correct; the type inference engine requires that all the "input" types of a lambda be known before the "output" type of the lambda is inferred)
public void Run()
{
var k = Generator((str, parent) => new {
Name = str,
Parent = parent
});
}
public Func<string, T, T> Generator<T>(Func<string, T, T> generator)
{
return (str, obj) => generator(str, obj);
}
This snippet fails to compile with an error that the compiler cannot infer the <T> to use with Generator<T>... thus I think it's impossible.

Categories

Resources