I am using a shorthand version for a class, which looks like this:
using NodeSteps = Tuple<Node, int>;
Node is a class defined by myself. This works fine usually, but the problem here is, is that Node is a generic requiring a struct.
My questions are as follows:
1.
How are these typedefs called in C#. I know they are not exactly typedefs, but it was the most similar thing I could think of.
2.
How can I make a generic version?
using NodeSteps<T> = Tuple<Node<T>, int>;
I noticed this is not the way to do it. I also would like to specify T is a struct.
Use
class NodeSteps<T> : Tuple<Node<T>, int>
{
}
This is the closest equivalent to a typedef I know of. If there are any non-default constructors, you would need to declare them, though.
They are called aliases.
No, this isn't possible. C# Language spec:
Using aliases can name a closed constructed type, but cannot name an unbound generic type declaration without supplying type arguments.
Therefore, using x<T> = List<T> or something similar isn't possible.
You may use a class (see the other answers(s)) instead.
This is covered in section 9.4.1 of the C# Language spec.
Using aliases can name a closed constructed type, but cannot name an
unbound generic type declaration without supplying type arguments.
This is called alias and can not be generic, but right hand of the using can be generic
using ListOfInts = List<int>
is valid
using NodeSteps = Tuple<Node, int>;
is not the equivalent of a typdef but just an alias to that class. It's designed to work around namespace collisions without having to use the whole namespace. What I would do is define a new class:
public class NodeSteps<T> : Tuple<Node<T>, int> where t: struct
{
}
This works:
namespace Test1
{
class Node<T>
{
public T Test()
{
return default(T);
}
}
}
namespace Test1
{
using NodeSteps = System.Tuple<Node<string>, int>;
public class Class1
{
public static void Main()
{
NodeSteps t1 = new NodeSteps(new Node<string>(), 10);
t1.Item1.Test();
}
}
}
Related
I have built myself a generic collection class which is defined like this.
public class StatisticItemHits<T>{...}
This class can be used with int and string values only. However this
public class StatisticItemHits<T> where T : string, int {...}
won't compile. What am I doing wrong?
The type restriction is meant to be used with Interfaces. Your sample suggests that you want to allow classes that inherit from int and string, which is kinda nonsense. I suggest you design an interface that contains the methods you'll be using in your generic class StatisticItemHits, and use that interface as restriction. However I don't really see your requirements here, maybe you could post some more details about your scenario?
You could make StatisticItemHits<T> an abstract class and create two subclasses:
StatisticItemHitsInt : StatisticItemHits<int>{}
StatisticItemHitsString : StatisticItemHits<string>{}
That way there can only be an int and string-representation of StatisticItemHits
As others have said, you cannot use type restrictions in this way. What you can do is to specialise from your base type as follows:
public class StatisticItemHits <T> { }
public class StringStatisticItemHits : StatisticItemHits<string> { }
public class IntegerStatisticItemHits : StatisticItemHits<int> { }
Also, as your base class is generic, you won't be able to use this to polymorphically. If you need to do this make StatisticItemHits implement an interface and use this to reference instances. Something like:
public class StatisticItemHits <T> : IStaticticItemHits { }
public interface IStatisticItemHits { }
You cannot restrict it to string and int from the where clause. You can check it in the constructor, but that is probably not a good place to be checking. My approach would be to specialize the class and abstract the class creation into a (semi-)factory pattern:
class MyRestrictedGeneric<T>
{
protected MyRestrictedGeneric() { }
// Create the right class depending on type T
public static MyRestrictedGeneric<T> Create<T>()
{
if (typeof(T) == typeof(string))
return new StringImpl() as MyRestrictedGeneric<T>;
if (typeof(T) == typeof(int))
return new IntImpl() as MyRestrictedGeneric<T>;
throw new InvalidOperationException("Type not supported");
}
// The specialized implementation are protected away
protected class StringImpl : MyRestrictedGeneric<string> { }
protected class IntImpl : MyRestrictedGeneric<int> { }
}
This way you can limit the class's usage to just string and int internally inside your class.
Given that you only have two types here I would go down an OO route here instead and just have two classes for the two types.
Generics are best used where the circumstances in which they can be applied are, you know, generic. They're a lot less use in circumstances like this.
You can restrict to struct or class types only, and I do think that there need to be numeric or operator based restrictions (e.g. must support +=)
Int and string are really quite different, certainly more different than int and double. It wouldn't make much sense for a generic class to support the immutable reference type of string and the value type of int without also supporting other types more similar to either of them.
Not possible to do this with 'where'. You can't do an 'or'.
Simply use:
where TSource : IEquatable<string>
Checking this:
https://riptutorial.com/csharp/example/8137/where
hybrid value/reference type
Occasionally it is desired to restrict type arguments to those
available in a database, and these will usually map to value types and
strings. As all type restrictions must be met, it is not possible to
specify where T : struct or string (this is not valid syntax). A
workaround is to restrict type arguments to IConvertible which has
built in types of "... Boolean, SByte, Byte, Int16, UInt16, Int32,
UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char, and
String." ...
public class Cup<T> where T : IConvertible
{
// ...
}
I solved the same problem you have with this solution, see my working example here:
static void Main()
{
var r1 = TryTest<int>(123); //Unmanaged supported
var r2 = TryTest<DateTime>(DateTime.Now); //Unmanaged supported
var r3 = TryTest<double>(123.55); //Unmanaged supported
var r4 = TryTest<string>("Homer Simpson"); //String supported
}
public static List<T> TryTest<T>(T someValue) where T : IConvertible
{
var list = new List<T>(); // Just for the sake of the example, a list of <T>
list.Add(someValue); //Add it...
return list;
}
The result will be a List of each type, string included. (Use watch to confirm)
I'm trying to generate code for series of generic classes using T4.
I want to know how to get full class name using reflection?
public class Foo<TFirst, TSecond> {}
var type = typeof(Foo<,>);
var name = type.FullName; // returns "Foo`2"
what I want is full name with actual generic parameter names that I've written
"Foo<TFirst, TSecond>"
Note that they are not known type, as I said I'm generating code using T4, so I want to have exact naming to use it for code generations, as an example, inside generic methods.
I tried this answers but they require to pass known type which is not what I want.
You can access the type parameter names by reflection using Type.GetGenericArguments:
using System;
public class Foo<TFirst, TSecond> {}
class Test
{
static void Main()
{
var type = typeof(Foo<,>);
Console.WriteLine($"Full name: {type.FullName}");
Console.WriteLine("Type argument names:");
foreach (var arg in type.GetGenericArguments())
{
Console.WriteLine($" {arg.Name}");
}
}
}
Note that that's giving the type parameter names because you've used the generic type definition; if you used var type = typeof(Foo<string, int>); you'd get String and Int32 listed (as well as a longer type.FullName.)
I haven't written any T4 myself, so I don't know whether this is any use to you - in order to get to Foo<TFirst, TSecond> you'd need to write a bit of string manipulation logic. However, this is the only way I know of to get at the type arguments/parameters.
I am trying to create an alias for a type of list of list of object. Specifically, I want to shorten all the typing I have to do for this type:
IReadOnlyList<IReadOnlyList<MyObject>>
My attempt is demonstrated here:
using System.Collections.Generic;
namespace MyApp
{
class Program
{
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return b.AsReadOnly();
}
}
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
static void Main(string[] args)
{
var collection = MyObject.GetCollection();
}
}
}
Unfortunately, this won't compile. There error is:
Cannot implicitly convert type
'System.Collections.ObjectModel.ReadOnlyCollection<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>'
to 'MyApp.Program.IMyCollection'.
An explicit conversion exists (are you missing a cast?)
OK, so I'm close. Perhaps explicitly casting? So I change the return statement in GetCollection to
return (IMyCollection)b.AsReadOnly();
That compiles, albeit with a resharper warning: Suspicious cast: there is no type in the solution which is inherited from both 'System.Collections.ObjectModel.ReadOnlyCollection>' and 'MyApp.Program.IMyCollection'
And at runtime, I get an invalid cast exception: Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyCollection1[System.Collections.Generic.IReadOnlyList1[MyApp.Program+MyObject]]' to type 'IMyCollection'.
OK, I can accept all that. I'm the last person to ask about stuff like covariance and contravariance and stuff like that. But surely there's a way to define and create an object with a short name to stand in for a really long named datatype.
How can I create a type with a really long name and cast to a type with a really short name?
UPDATE:
A co-worker suggested using a using statement.
using IMyCollection= System.Collections.Generic.IReadOnlyList<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>;
While that would work, it then becomes necessary to do that in every file that uses IMyCollection. Not exactly what I would consider a solution to my goal.
How badly do you want this?
You can manually implement your own wrapper class.
public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>>
{
}
public class MyCollectionImpl : IMyCollection
{
private readonly IReadOnlyList<IReadOnlyList<MyObject>> _wrappedCollection;
public MyCollectionImpl(IReadOnlyList<IReadOnlyList<MyObject>> wrappedCollection)
{
_wrappedCollection = wrappedCollection;
}
public int Count
{
get
{
return _wrappedCollection.Count;
}
}
public IReadOnlyList<MyObject> this[int index]
{
get
{
return _wrappedCollection[index];
}
}
public IEnumerator<IReadOnlyList<MyObject>> GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _wrappedCollection.GetEnumerator();
}
}
Then you simply create an instance of this:
public class MyObject
{
public static IMyCollection GetCollection()
{
var a = new List<MyObject>();
a.Add(new MyObject());
var b = new List<IReadOnlyList<MyObject>>();
b.Add(a.AsReadOnly());
return new MyCollectionImpl(b.AsReadOnly());
}
}
This seems like a lot of extra work, but I would actually consider this a refactoring step.
I believe that the need to pass around types made up of complex set of generic parameters, is actually a bad smell in your code.
Ask yourself, what are you actually using IMyCollection for? Would you be able to add some specialized methods to this interface to make it easier to use?
Once you've created your own MyCollectionImpl class you can slowly add a number of methods to your IMyCollection interface to simplify it's usage. At some point, you might even get to the stage where you can stop exposing the <IReadonlyList<IReadonlyList<MyObject>> interface.
This has nothing to do with covariance. IMyCollection inherits from IReadOnlyList<IReadOnlyList<MyObject>> so you can cast an instance of IMyCollection to IReadOnlyList<IReadOnlyList<MyObject>> but not the other way around.
If you wanna have some custom conversions then you can create a type instead with the short name you want and declare a conversion from IReadOnlyList<IReadOnlyList<MyObject>> to your type using operator overloading. This really seems unnecessary and unusual way to use operator overloading but it's the only way to do what you want to achieve.
Since I am using two different generic collection namespaces (System.Collections.Generic and Iesi.Collections.Generic), I have conflicts. In other parts of the project, I am using both the nunit and mstest framework, but qualify that when I call Assert I want to use the nunit version by
using Assert = NUnit.Framework.Assert;
Which works great, but I want to do the same thing with generic types. However, the following lines do not work
using ISet = System.Collections.Generic.ISet;
using ISet<> = System.Collections.Generic.ISet<>;
Does anyone know how to tell .net how to use the using statement with generics?
Unfortunately, the using directive does not do what you want. You can say:
using Frob = System.String;
and
using ListOfInts = System.Collections.Generic.List<System.Int32>;
but you cannot say
using Blob<T> = System.Collections.Generic.List<T>
or
using Blob = System.Collections.Generic.List
It's a shortcoming of the language that has never been rectified.
I think you're better off aliasing the namespaces themselves as opposed to the generic types (which I don't think is possible).
So for instance:
using S = System.Collections.Generic;
using I = Iesi.Collections.Generic;
Then for a BCL ISet<int>, for example:
S.ISet<int> integers = new S.HashSet<int>();
The only way you can alias a generic type is to specialize it as follows.
using IntSet = System.Collections.Generic.ISet<int>;
You can not alias an open generic type as you have done in your example:
using MySet = System.Collections.Generic.ISet<>;
Your alias name is the same as the class name itself, so you still have ambiguity, just as if you had a using for each namespace. Give the alias of the class a different name, i.e.:
using FirstNamespace;
using OtherObject = SecondNamespace.MyObject;
public class Foo
{
public void Bar()
{
MyObject first = new MyObject;//will be the MyObject from the first namespace
OtherObject second = new OtherObject;
}
}
In some cases you can go with inheritance:
public class MyList<T1, T2> : List<Tuple<IEnumerable<HashSet<T1>>, IComparable<T2>>> { }
public void Meth()
{
var x = new MyList<int, bool>();
}
You can alias a class doing :
using Test = NameSpace.MyClass;
Only if the class is NOT generic.
Can I locally reference a class in C#, instead of an instance of a class? The following code won't compile but, as an example, something like:
void someFunc()
{
var a = System.Math;
var b = a.Abs(4);
}
edit: In the real program it's not the System.Math class and I'm wanting to construct the class and return the constructed value. I didn't think originally that the context in which I wanted to use the class would be relevent, and probably it shouldn't be.
Anastasiosyal has an interesting idea with using a local Delegate to do it.
You can reference a class:
Type math = typeof(System.Math);
But you cannot call static methods on it using regular dot syntax:
// Wont compile:
math.Abs(5);
If you just want to shorten (and IMHO obfuscate) your code, you can reference classes with aliases via a using directive:
// Untested, but should work
namespace MyUnreadableCode {
using m = System.Math;
class Foo {
public static Int32 Absolut(Int32 a) {
return m.Abs(a);
}
}
}
You cannot assign a variable a value of a static class. The question is why would you want to do this, there are probably other ways that you could tackle your problem
e.g. you could use delegates to assign the operation you want to perform:
Func<int,int> operation = Math.Abs;
// then you could use it like so:
int processedValue = operation(-1);
In c# they're called Types. And you can assign them like:
Type a = typeof(SomeClass);
However, you would have to instantiate it to use it. What I believe you want is a static import like in java, but unfortunately, they do not exist in c#.
Short answer: Not like what you have above.
In C# 6.0 they introduced a static import feature, which can solve the problem.
using static System.Math;
class MyProgram
{
static void Main(string[] args)
{
var b = Abs(4); // No need to specify the name of Math class
}
}
As I understand you need to refer to the class with short name? try this (on top of the file, inside using statements section):
using m = System.Math;
later in your code:
m.Abs(...)
Makes sense?
No. It's not possible to treat a Type as a value where instance methods bind to static methods on the original type. In order to do this you would need to construct a new type which forwards it's method calls to the original type.
class MyMath {
public int Abs(int i) {
return Math.Abs(i);
}
}
var x = new MyMath();