How to use generic declared variable in C# - c#

public static object GetObject(int x)
{
return new object { };
}
public static object GetObject(string x)
{
return new object { };
}
public static void ProcessObject<T>(T x) where T : int, string <= got error here:
{
object o = GetObject(x);
}
Got error "A type used as a constraint must be an interface, a non-sealed class or a type parameter."
How can I rewrite the code to get it work without write ProcessObject(int x) and ProcessObject(string x) twice?

So what you have now (according to accepted answer and your comments) is:
public static void ProcessObject<T>(T x)
{
object o;
if (typeof(T) == typeof(int))
o = GetObject((int)(object)x);
else if (typeof(T) == typeof(string))
o = GetObject((string)(object)x);
else
throw new Exception();
// do stuff with o
}
I'd recommend making public int and string overloads, but to prevent code duplication, internally call another method:
public static void ProcessObject(int x)
{
ProcessObject(GetObject(x));
}
public static void ProcessObject(string x)
{
ProcessObject(GetObject(x));
}
private static void ProcessObject(object o)
{
// do stuff with o
}
This makes your public methods' input values clear: int and string are the only acceptable types, while still not duplicating your actual logic (// do stuff with o).
You might dislike that the two public ProcessObject methods are duplicates of each other, (on the surface anyway; under the hood, they're calling two different GetObject overloads) but I think it's the best option.

You cannot do what you are trying to do: first, it is not possible to list several classes in a generic constraint; second, the type that you can put in a constraint must be such that you could inherit it (or implement it if it is an interface). Both int and string fail this check. In cases like this, you would be better off with two separate overloads.

Just remove the where part
public static void ProcessObject<T>(T x)
{
object o = GetObject(x);
}
And also don't use object in your other methods, instead use T

it's impossible in C# take a look on Constraints on Type Parameters. Try to use dynamic

Generally speaking, if your object reacts differently based on the generic type argument, you probably shouldn't be using generics in this case. Generics are great for situations where you want to do always the same thing, no matter what the actual type used.
Therefore, generic constraints will only allow you to list one base class for a type argument. Any actual types passed to the respective type arguments are meant to be a part of the given inheritance hierarchy starting with the base class you specified, so users of your class can specify any type that matches the base class or any of its subclasses.
At the same time, you, the author of the generic class, can safely assume that the specified type has (at least) the interface of the base class indicated by the constraint. Hence, you may access any members of the base class.
If you want to allow either string or int, imagine what members that could be. Both are derived directly from System.Object, hence the restriction would make no sense as it is no restriction; every type is derived from System.Object.
Summarizing, if you really want to treat string and int differently, this is definitely a case for offering two overloads rather than one generic class.

Related

Casting of generic type does not compile

Please have a look at the following code. Why do I get a compile-error?
I don't get it!
Casting is a way of telling the compiler that I know more about the objects than it does. And in this case, I know for fact, that "x" does actually contain an instance of "SomeClass". But the compiler seems to be unwilling to accept that information.
https://dotnetfiddle.net/0DlmXf
public class StrangeConversion
{
public class SomeClass { }
public interface ISomeInterface { }
public class Implementation : SomeClass, ISomeInterface { }
public void Foo<T>() where T : class
{
T x = (T)Factory();
//Compile-error: Cannot convert type 'T' to 'SomeClass'
SomeClass a = (SomeClass)x;
//This is perfectly fine:
SomeClass b = (SomeClass)(object)x;
if (x is SomeClass c)
{
//This works as well and 'c' contains the reference.
}
}
private object Factory()
{
return new Implementation();
}
}
Edit:
#Charles Mager has the correct answer in the comment: There does not seem to be a valid reason. The language designers just didn't want to allow this cast.
I fixed using the as casting e.g.
SomeClass a = x as SomeClass;
This Answer explains is very well https://stackoverflow.com/a/132467/16690008
Essentially it's because it would throw an exception if T is not type of that class
It's hard to make sense of exactly what you're trying to achieve, but it seems like a generic constraint is what you're after
public void Foo<T>()
where T : SomeClass // constrain T to be inheriting from SomeClass
{
T x = Factory<T>(); // x is guaranted to be SomeClass
}
private T Factory<T>()
where T : SomeClass // same here
{
return new Implementation();
}
You constrain the generic to only reference types by specifying where T : class, but the compiler needs to know with certainty if the cast is possible. This means you are asking the compiler to trust that SomeClass can be cast from any reference type you pass to it, which is something it won't do. The microsoft docs state that for the class generic type constraint:
The type argument must be a reference type. This constraint applies also to any class, interface, delegate, or array type.
Its important to note that SomeClass b = (SomeClass)(object)x; works because of the cast to object which is the root of the object hierarchy. But as you can see from the list of supported reference types, SomeClass a = (SomeClass)x; has to account for things such as delegates, array types, etc., at which point the compiler will throw you the error
Don't do SomeClass b = (SomeClass)(object)x;, it is much cleaner to make proper use of type constraints along with the as & is operators which were designed for this exact purpose of type checking and safe casting
Short answer:
This behaviour is correct according to the spec. The spec is just bad here since this might convert a compile-error into a runtime-error.
Long answer:
I did some more research on the matter. This is an oversight in the language's spec.
C# uses the same syntax for two totally different things:
int i = (int)1.9
This converts the double 1.9 to an integer. The value is actually changed.
object o = "abc";
string s = (string) o;
This looks the same, but does not change the object referenced by "o" at all. It does only convert the type of the reference.
When it comes to generics, this kind of ambiguity is an issue:
function f(T x) {
var x = (string) x;
}
What should the language do if T is "int"?
That's why the spec forces the developer to cast to object first:
function f(T x) {
var x = (string)(object)x;
}
Now, the behaviour is clear: X might still be a value-type. But if it is, it will be converted to a reference-type first.
This ambiguity does not exist in my example, since T is guaranteed to be a reference type:
public void Foo<T>() where T : class
Thus the cast to object is not necessary. It could even be harmful if the "where" specifies an actual type. In that case, the forced cast to object might convert a compile-time-error (impossible cast) to a runtime-error.
Unfortunately, the people who created the spec, did not see this issue and did not include it.

Phantom generic constraints in C#

I came across this problematic quite often: I like to overload some method with same parameters for different return types, but .NET refuses generic constraints to sealed classes/primitives. I'll refer to this pattern as phantom generics.
I know an ugly workaround: Putting every single interface the type implements behind the where statement.
My Question: Is there any way to use explicit types in generics to illustrate the return type and keep methods distinct?
Here is my code:
public static class Reinterpret {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(int value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value); //reinterpret the bytes of 'value' to a float
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe float Cast<T>(uint value) where T : float { //'float' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((float*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(long value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe double Cast<T>(ulong value) where T : double { //'double' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
return *((double*)&value);
}
}
Here's one slightly different way of approach it:
// Constraints just to be vaguely reasonable.
public static class Reinterpret<T> where T : struct, IComparable<T>
{
public T Cast(int value) { ... }
public T Cast(uint value) { ... }
public T Cast(float value) { ... }
public T Cast(double value) { ... }
// etc
}
For the implementation, you could just have a Func<int, T> field, a Func<double, T> field etc, and then have a big static constructor:
static Reinterpret()
{
if (typeof(T) == typeof(int))
{
// Assign all the fields using lambda expressions for ints.
// The actual assignment might be tricky, however - you may
// need to resort to some ghastly casting, e.g.
castDouble = (Func<double, T>)(Delegate)(Func<double, int>)
x => *((double*)&value;
}
....
}
Then for any type you didn't want to support, the fields would be null. Each Cast method would look like:
if (castIntMethod != null)
{
return castInt(value);
}
throw new InvalidOperationException("...");
To be honest, this isn't something I'd really want to do. I'd generally just use BitConverter. But it's an option.
Generics are not templates. They do not act like templates. They cannot be made to act like templates.
A "phantom" generic parameter is not going to help you simulate templates (and reinterpret_cast is not an actual template, anyway), because you soon are going to run into the fact that generics do not support specialization.
In particular, you asked "Is there any way to use explicit types in generics to ... keep methods distinct?" and commented that "the generic constraints ... keeps [sic] the methods distinct". But they actually do not. These methods are distinct only because the argument types are different. Generics are computed from overloads, they do not influence overloading.

generic return type based on a Type paramater in C#

I have a class with a dictionary that maps Type keys to objects that implement some interface IWhatever.
I wish to create a generic function that gets a Type as input and returns the object mapped to that type in the dictionary.
Something like :
public T get<T>(Type type)
Where T is an instance of type and type implements IWhatever.
I don't want to return Object or even Iwhatever but objects of the given type. the type of the return objects can clearly be infered at compile time. so I assume it should be possible.
I have managed to do this in java:
public T get<T>(Class<T extends IWhatever> type) { // implementation }
Is there any way to achieve this in C# ? if not, why not and what alternatives would you suggest ?
I think you want:
public T Get<T>() where T : IWhatever { ... }
For more information, see Constraints on Type Parameters (C# Programming Guide).
This is of course only useful when the client can provide the type argument easily at compile-time. Internally, your method may need a lot of nastiness, e.g.:
return (T) myDict[typeof(T)];
I think you are being misled by Java's erasure. Consider the following Java code from your post (edited to make it valid code):
public <T extends IWhatever> T get(Class<T> type) { // implementation }
In this case, the type parameter is only required because the generic type information is only available at compile time. This is not true in C#, where you can write the following:
public T Get<T>()
where T : IWhatever
{
Type type = typeof(T);
// rest of implementation
}
From your first two sentences, what you want I think is the following. You have to decide on some attribute of your types that will be unique. You could make sure that all the types you have include the GUID attribute.
public class MyClass
{
private Dictionary<GUID, object> _myDictionary;
public AddObject(object objectToAdd)
{
_myDictionary.Add(objectToAdd.GUID, objectToAdd);
}
public object GetObject(Type typeToGet)
{
return _myDictionary[typeToGet.GUID];
}
}
If the dictionary needs to contain multiple objects of each type, then the dictionary values can be lists of objects.

Why are type parameters not allowed in constructors?

There are type parameters for methods. Why there are no type parameters for constructors?
Example
I think there are several (not many) examples where it would be usefull. My current problem was following:
internal class ClassA
{
private readonly Delegate _delegate;
public ClassA<T>(Func<T> func)
{
_delegate = func;
}
}
A Delegate is enough for my class. But to pass it as method group I need to define the parameter as a Func<T>.
After reading the C# specification it actually does make sense, but it can be confusing.
Each class has an associated instance type, and for a generic class declaration the instance type is formed by creating a constructed type from the type declaration, with each of the supplied type arguments being the corresponding type parameter.
class C<T>
{
}
C<T> is a constructed type, and an instance type will be created by the process of constructing the type using the type parameters.
C<String> c = new C<String>();
The compiler took the constructed type C<T>, and using the supplied type parameters an instance type of C<String> was created. Generics is only a compile time construct, everything is executed in the terms of closed constructed types at runtime.
Now let's take your question and put it to the test here.
class C
{
public C<T>()
{
}
}
This isn't possible, because you are trying to construct a type that doesn't exist.
C c = new C<String>();
What is the implicit or explicit conversion between C and C<String>? There is none. It doesn't even make sense.
Because C is a non-generic type in this example, the instance type is the class declaration itself. So how do you expect C<String> to construct C?
The proper declaration for what you want to do is this.
internal class Class<T>
{
private readonly Delegate _delegate;
public Class(Func<T> function)
{
_delegate = function;
}
}
Here because we have a constructed type Class<T>, the proper instance type can be created by the compiler.
Func<String> function = new Func<String>(() => { return String.Empty; });
Class<String> c = new Class<String>(function);
If you tried to do it the way you want in your question.
Func<String> function = new Func<String>(() => { return String.Empty; });
Class c = new Class<String>(function);
The constructed type would be Class<String>, which is not the same as type C, and there is no implicit or explicit conversion from either one. If this was allowed by the compiler, C would be in some unknown and unusable state.
What you do need to know about constructed types, is this.
class C<T>
{
public C<T>()
{
}
}
While you cannot explicitly declare a generic constructor, it is valid but only as a closed type constructor at runtime.
C<String> c = new C<String>();
At compile time, the following constructor is created.
public C<String>()
{
}
Which is why this is valid:
C<String> c = new C<String>(); // We just used the closed type constructor
If what you wanted was allowed, something like this could happen.
class C<T>
{
public C<U>()
{
}
}
// ???
C<String> c = new C<Int32>();
You can see the problems now that would arise if the construct was allowed. Hopefully this sheds some insight, the specification is rather long and there are many many many sections that cover generics, type parameters, constructed types, closed and open types, bound and unbound.
It can get very confusing, but its a good thing that this isn't allowed by the compiler rules.
They simply didn't include the feature, probably on the assumption that it wouldn't be very useful.
If you need it for the constructor, you probably need it for the whole type. But in the cases you don't, you can probably use Object anyway.
And if you can't... yeah, I don't think there's much of a way around it, sorry. :\ You can use reflection but of course that'd be ridiculously slow... or you could play tricks with generating methods dynamically, which might be worth it depending on your use case but which might also be slow (it adds at least 1 extra indirect call).
Because a constructor is part of a class and so the type parameters probably belong on the whole type.
If you can choose a different type parameter to use when constructing an instance of a generic class then you are really constructing a different type of class. I know it's not the same as templated classes in C++ but the concept is similar.
To solve your particular issue you could use a 'templated' factory method.
You can pass in a delegate instead of a strongly typed Func<T>. You will not be able to know the type at compile time, but you wouldn't have that when you pass in the Func<T> either. When you want that you'd have to make the whole class generic.
class Program {
static void Main(string[] args) {
Func<int> i = () => 10;
var a1 = new ClassA(i);
Func<string> s = () => "Hi there";
var a2 = new ClassA(s);
}
}
internal class ClassA {
private readonly Delegate _delegate;
public ClassA(Delegate func) { // just pass in a delegate instead of Func<T>
_delegate = func;
}
}
Because you can achive that by declaring your class as generic
internal class ClassA<T>
{
private readonly Delegate _delegate;
public ClassA(Func<T> func)
{
_delegate = func;
}
}
then you will have implicitly a generic construct

Generic type checking

Is there a way to enforce/limit the types that are passed to primitives? (bool, int, string, etc.)
Now, I know you can limit the generic type parameter to a type or interface implementation via the where clause. However, this doesn't fit the bill for primitives (AFAIK) because they do not all have a common ground (apart from object before someone says! :P).
So, my current thoughts are to just grit my teeth and do a big switch statement and throw an ArgumentException on failure.
EDIT 1:
Just to clarify:
The code definition should be like this:
public class MyClass<GenericType> ....
And instantiation:
MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)
EDIT 2
#Jon Limjap - Good point, and something I was already considering. I'm sure there is a generic method that can be used to determine if the type is of a value or reference type.
This could be useful in instantly removing a lot of the objects I don't want to deal with (but then you need to worry about the structs that are used such as Size ). Interesting problem no? :)
Here it is:
where T: struct
Taken from MSDN.
I'm curious. Could this be done in .NET 3.x using extension methods? Create an interface, and implement the interface in the extension methods (which would probably be cleaner than a bit fat switch). Plus if you then need to later extend to any lightweight custom types, they can also implement the same interface, with no changes required to the base code.
What do you guys think?
The sad news is I am working in Framework 2!! :D
EDIT 3
This was so simple following on from Jon Limjaps Pointer.. So simple I almost want to cry, but it's great because the code works like a charm!
So here is what I did (you'll laugh!):
Code added to the generic class
bool TypeValid()
{
// Get the TypeCode from the Primitive Type
TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));
// All of the TypeCode Enumeration refer Primitive Types
// with the exception of Object and Empty (Null).
// Since I am willing to allow Null Types (at this time)
// all we need to check for is Object!
switch (code)
{
case TypeCode.Object:
return false;
default:
return true;
}
}
Then a little utility method to check the type and throw an exception,
private void EnforcePrimitiveType()
{
if (!TypeValid())
throw new InvalidOperationException(
"Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name +
"' - this Class is Designed to Work with Primitive Data Types Only.");
}
All that then needs to be done is to call EnforcePrimitiveType() in the classes constructors. Job done! :-)
The only downside, it only throws an exception at runtime (obviously) rather than design time. But that's no big deal and could be picked up with utilities like FxCop (which we don't use at work).
Special thanks to Jon Limjap on this one!
public class Class1<GenericType> where GenericType : struct
{
}
This one seemed to do the job..
Primitives appear to be specified in the TypeCode enumeration:
Perhaps there is a way to find out if an object contains the TypeCode enum without having to cast it to an specific object or call GetType() or typeof()?
Update It was right under my nose. The code sample there shows this:
static void WriteObjectInfo(object testObject)
{
TypeCode typeCode = Type.GetTypeCode( testObject.GetType() );
switch( typeCode )
{
case TypeCode.Boolean:
Console.WriteLine("Boolean: {0}", testObject);
break;
case TypeCode.Double:
Console.WriteLine("Double: {0}", testObject);
break;
default:
Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
break;
}
}
}
It's still an ugly switch. But it's a good place to start!
Pretty much what #Lars already said:
//Force T to be a value (primitive) type.
public class Class1<T> where T: struct
//Force T to be a reference type.
public class Class1<T> where T: class
//Force T to be a parameterless constructor.
public class Class1<T> where T: new()
All work in .NET 2, 3 and 3.5.
If you can tolerate using factory methods (instead of the constructors MyClass you asked for) you could always do something like this:
class MyClass<T>
{
private readonly T _value;
private MyClass(T value) { _value = value; }
public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
// etc for all the primitive types, or whatever other fixed set of types you are concerned about
}
A problem here is that you would need to type MyClass<AnyTypeItDoesntMatter>.FromInt32, which is annoying. There isn't a very good way around this if you want to maintain the private-ness of the constructor, but here are a couple of workarounds:
Create an abstract class MyClass. Make MyClass<T> inherit from MyClass and nest it within MyClass. Move the static methods to MyClass. This will all the visibility work out, at the cost of having to access MyClass<T> as MyClass.MyClass<T>.
Use MyClass<T> as given. Make a static class MyClass which calls the static methods in MyClass<T> using MyClass<AnyTypeItDoesntMatter> (probably using the appropriate type each time, just for giggles).
(Easier, but certainly weird) Make an abstract type MyClass which inherits from MyClass<AnyTypeItDoesntMatter>. (For concreteness, let's say MyClass<int>.) Because you can call static methods defined in a base class through the name of a derived class, you can now use MyClass.FromString.
This gives you static checking at the expense of more writing.
If you are happy with dynamic checking, I would use some variation on the TypeCode solution above.
You can simplify the EnforcePrimitiveType method by using typeof(PrimitiveDataType).IsPrimitive property. Am I missing something?
#Rob, Enum's will slip through the TypeValid function as it's TypeCode is Integer. I've updated the function to also check for Enum.
Private Function TypeValid() As Boolean
Dim g As Type = GetType(T)
Dim code As TypeCode = Type.GetTypeCode(g)
' All of the TypeCode Enumeration refer Primitive Types
' with the exception of Object and Empty (Nothing).
' Note: must also catch Enum as its type is Integer.
Select Case code
Case TypeCode.Object
Return False
Case Else
' Enum's TypeCode is Integer, so check BaseType
If g.BaseType Is GetType(System.Enum) Then
Return False
Else
Return True
End If
End Select
End Function
Having a similar challenge, I was wondering how you guys felt about the IConvertible interface. It allows what the requester requires, and you can extend with your own implementations.
Example:
public class MyClass<TKey>
where TKey : IConvertible
{
// class intentionally abbreviated
}
I am thinking about this as a solution, all though many of the suggested was part of my selection also.
My concern is - however - is it misleading for potential developers using your class?
Cheers - and thanks.
Use a custom FxCop rule that flags undesirable usage of MyClass<>.
In dotnet 6, I encountered this error when using struct:
The type 'string' must be a non-nullable value type in order to use it as parameter 'T'
So I use IConvertible instead
var intClass = new PrimitivesOnly<int>();
var doubleClass = new PrimitivesOnly<double>();
var boolClass = new PrimitivesOnly<bool>();
var stringClass = new PrimitivesOnly<string>();
var myAwesomeClass = new PrimitivesOnly<MyAwesomeClass>(); // illegal
// The line below encounter issue when using "string" type
// class PrimitivesOnly<T> where T : struct
class PrimitivesOnly<T> where T : IConvertible
{
}
class MyAwesomeClass
{
}

Categories