Ambiguous reference with generic class [duplicate] - c#

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.

Related

Error using reflection, when trying to get the type

I am trying to use reflection.
Here is my function using reflection:
name = "IfcPolyLoop"
polyLoopLine="#99= IFCPOLYLOOP((#101,#103,#105,#107));"
private void convertFirstIfcPolyLoop(string typeName,string polyLoopLine)
{
var type = Type.GetType(typeName);
object instance = Activator.CreateInstance(type, polyLoopLine, this.listDictionaries);
this.AddOrError((IfcElement)instance);
}
What I want to do is something equivalent to that :
private void convertFirstIfcPolyLoop(string polyLoopLine)
{
IfcPolyLoop newElt = new IfcPolyLoop(polyLoopLine, this.listDictionaries)
}
But I want to use reflection.
But when I do var type = Type.GetType(typeName);, type is still set to null, and I think I am supposed to obtain IfcPolyLoop
Although the classes are in the same namespaces, you need to provide the class name along with the namespace.
So for example you need to pass YourNamespace.YourClassName as the string value to the Type.GetType method.
In my case, it worked when passing as "ConsoleApp1.Program2" for the class Program2 in ConsoleApp1 namespace.

name of class with generic parameters?

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.

C# typedef generics

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();
}
}
}

c# class reference as opposed to instance reference

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();

Dynamically create an object of <Type>

I have a table in my database that I use to manage relationships across my application. it's pretty basic in it's nature - parentType,parentId, childType, childId... all as ints. I've done this setup before, but I did it with a switch/case setup when I had 6 different tables I was trying to link. Now I have 30 tables that I'm trying to do this with and I would like to be able to do this without having to write 30 case entries in my switch command.
Is there a way that I can make reference to a .Net class using a string? I know this isn't valid (because I've tried several variations of this):
Type t = Type.GetType("WebCore.Models.Page");
object page = new t();
I know how to get the Type of an object, but how do I use that on the fly to create a new object?
This link should help:
https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance
Activator.CreateInstance will create an instance of the specified type.
You could wrap that in a generic method like this:
public T GetInstance<T>(string type)
{
return (T)Activator.CreateInstance(Type.GetType(type));
}
If the type is known by the caller, there's a better, faster way than using Activator.CreateInstance: you can instead use a generic constraint on the method that specifies it has a default parameterless constructor.
Doing it this way is type-safe and doesn't require reflection.
T CreateType<T>() where T : new()
{
return new T();
}
public static T GetInstance<T>(params object[] args)
{
return (T)Activator.CreateInstance(typeof(T), args);
}
I would use Activator.CreateInstance() instead of casting, as the Activator has a constructor for generics.
You want to use Activator.CreateInstance.
Here is an example of how it works:
using System;
using System.Runtime.Remoting;
class Program
{
static void Main()
{
ObjectHandle o = Activator.CreateInstance("mscorlib.dll", "System.Int32");
Int32 i = (Int32)o.Unwrap();
}
}
Assuming you have the following type:
public class Counter<T>
{
public T Value { get; set; }
}
and have the assembly qualified name of the type, you can construct it in the following manner:
string typeName = typeof(Counter<>).AssemblyQualifiedName;
Type t = Type.GetType(typeName);
Counter<int> counter =
(Counter<int>)Activator.CreateInstance(
t.MakeGenericType(typeof(int)));
counter.Value++;
Console.WriteLine(counter.Value);
Here is a function I wrote that clones a record of type T, using reflection.
This is a very simple implementation, I did not handle complex types etc.
public static T Clone<T>(T original)
{
T newObject = (T)Activator.CreateInstance(original.GetType());
foreach (var prop in original.GetType().GetProperties())
{
prop.SetValue(newObject, prop.GetValue(original));
}
return newObject;
}
I hope this can help someone.
Assaf

Categories