I have this extension method for an Enum:
public static List<Enum> Values(this Enum theEnum)
{
return Enum.GetValues(theEnum.GetType()).Cast<Enum>().ToList();
}
I'm getting a code analysis violation:
CA1062 Validate arguments of public methods
In externally visible
method 'EnumExtensions.Values(this Enum)', validate parameter
'theEnum' before using it.
Why is that happening? How can I validate the parameter? I can't check for null because an enum is a non-nullable value type. Is there some other check that is supposed to be occurring here?
I can't check for null because an enum is a non-nullable value type.
Any particular enum is a value type, but Enum itself isn't. (Just like ValueType isn't a value type either... every type derived from ValueType except Enum is a value type.)
In other words, I could write:
Enum foo = null;
var bang = foo.GetValues();
That would compile and then fail at execution time with a NullReferenceException.
Given that you ignore the value except to get its type, I'd actually suggest removing it and either accepting a Type or making it generic in the type of enum you want. But if you want to keep the current signature, you just need:
if (theEnum == null)
{
throw new ArgumentNullException();
}
You might also want to look at my Unconstrained Melody project which provides a bunch of helper methods for enums, generically constrained to enum types via IL manipulation.
The enum keyword is used to declare an enumeration, a distinct type that consists of a set of named constants called the enumerator list.
It is used just for declare another enums. In any case, the input should be your declaration.
public enum theEnum {
enum1,
enum2
}
public void ShowEnum(theEnum e)
{
System.Console.WriteLine(e.GetType());
}
Related
I want to define a function with a parameter, that paramter must be a specific, defined in a list (for example)
i remember doing this years ago but my memory has failed me.
example
public void foo(specific choice list defined in my class){}
specific-list = x,y,z
consume it list this (i think)
foo(myclass.x)
To expand on #kaffekopp's comment, it seems likely that you are talking about an enum, i.e.
public enum MyEnum // declare the enum type (optional: specify an underlying integer type)
{
Apple, // define the choices (note: enums are **not** strictly enforced;
Pear, // they are just named integers, and at runtime you can be surprised to find
Bicycle, // that the actual value is 42, a value you never defined)
}
with (on MyClass):
public MyEnum SomeProp {get;set;} // define a property as being of that enum type
and:
public void Foo(MyEnum option) {...} // define a method that takes a parameter of the type
then either:
Foo(MyEnum.Bicycle); // passing a constant/literal
or:
MyClass obj = ...
Foo(obj.SomeProp); // passing an existing value from somewhere
I have public functions like this:
public static T Get<T>(this Mango m, T defaultValue = default(T)) where T : class
{
//do something; return something;
}
public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
//do something; return something;
}
Basically I want to individually handle reference types and nullable types. It compiles; until i call for value types. For reference types it compiles.
mango.Get<string>(); // compiles..
mango.Get(""); // compiles..
mango.Get<int>(); // The type 'int' must be a reference type in order to use it as
// parameter 'T' in the generic type or method Get<T>(Mango, T)
//also // The call is ambiguous between the following methods or properties:
// Get<int>(Mango, int) and Get<int>(Mango, int?)
What real ambiguity is here? When T is int, cant it call the struct overload appropriately? Also:
mango.Get<int>(0); // The type 'int' must be a reference type in order to use it as
// parameter 'T' in the generic type or method Get<T>(Mango, T)
Why is the compiler only detecting the reference type overload? I tried having two separate overloads:
public static T Get<T>(this Mango m) where T : class
{
return default(T);
}
public static T? Get<T>(this Mango m) where T : struct
{
return default(T);
}
public static T Get<T>(this Mango m, T def) where T : class
{
return default(T);
}
public static T? Get<T>(this Mango m, T? def) where T : struct
{
return default(T);
}
The problem persisted. And obviously, the first two methods dont compile here since overloading doesn't work merely on the basis of constraints.
I tried by removing the class constrained overload and keeping just the struct constrained one, like this:
public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
//do something; return something;
}
mango.Get<int>(); // voila compiles!
mango.Get<int>(0); // no problem at all..
// but now I can't have mango.Get<string>() for instance :(
Am I only left with renaming the two functions? I feel its appropriate to have a unified name so that the caller just doesnt have to worry about the implementation detail, but just call Get for any type.
Update: Marc's solution doesnt work if I have to avoid the optional parameter.
mango.Get<int>(); // still wouldnt work!!
But there's more magic :(:(
public static bool IsIt<T>(this T? obj) where T : struct
{
return who knows;
}
public static bool IsIt<T>(this T obj) where T : class
{
return perhaps;
}
By all means I'm expecting the same compiler bug (according to me) to annoy me. But no it works this time.
Guid? g = null;
g.IsIt(); //just fine, and calls the struct constrained overload
"abcd".IsIt(); //just fine, and calls the class constrained overload
So if overload resolution comes before constraint checking as Marc says, shouldn't I get the same error this time too? But no. Why is it so?? What the hell is going on? :x
constraint checking is done after overload resolution, IIRC; the overload resolution seems to prefer the first version. You can force it to use the other, though:
mango.Get<int>((int?)0);
or even:
mango.Get((int?)0);
Personally, I'd probably just change the name to avoid the ambiguity.
Interestingly, the compiler will check the constraints specified within generic types that are used within a method signature, but not for constraints within the signature itself.
Thus, if a method accepted two parameters, one of type T where T : struct along with a Nullable<T>[], the compiler would not consider the method for any T that was not a struct. The method's specified struct constraint for T is not considered in evaluating overloads, but the fact that Nullable<T> constrains T to struct, is.
I really find the total inability to consider constraints in overload evaluation bizarre, given that one could specify a default null value for the Nullable<T>[] parameter, and pretend the parameter didn't exist. The vb.net compilers and C# compilers seem to differ, though, when it comes to what they regard as ambiguous and what they accept.
Let me try to answer myself.
As marc says, constraint checking is done after overload resolution, and between
public static T Get<T>(this Mango m, T defaultValue = default(T)) where T : class
{
//do something; return something;
}
and
public static T? Get<T>(this Mango m, T? defaultValue = default(T?)) where T : struct
{
//do something; return something;
}
overload resolution prefers the class version. But that's only when the compiler is given a choice between two similar overloads (without the optional parameter in which case both the overloads becomes the same, neglecting constraint). Now when the constraint is applied, the call fails for Get<int> since int is not class.
Things change a bit when default parameter is provided. If I call
mango.Get(0);
The compiler is able enough to call the right overload, but which overload now accepts int or T where T: struct? There is not one. In the given example, the second parameter is expected to be T? and not T. The compiler doesnt automatically resolve overloading by applying all the available casts for every argument type. It isn't a bug, but thats one less a feature, thats all. If I do this:
int? i = 0;
mango.Get(i);
it works, the right overload is called. This is what is happening in the second example too. It works because I'm providing the right parameter.
When I call:
Guid? g = null;
g.IsIt();
obj is known to be g and hence T equals Guid. But if I call
Guid g = Guid.NewGuid();
g.IsIt();
This doesn't work, since g is now Guid and not Guid? and compiler doesnt do the casting automatically, instead one have to tell the compiler explicitly.
I'm ok with the fact that the compiler doesn't do the casting automatically since that will be too much to calculate for every possible type, but what appears to be a deficiency in C# is the fact that constraint checking is not involved in overload resolution. That is even if I provide the type like mango.Get<int>() or mango.Get<int>(0) the overload resolution won't prefer the struct version and use default(int?) for argument defaultValue. Looks odd to me.
I have three enums:
enum ValueType : int
{
FloatingPoint = 2,
.../...
}
enum ConstraintType : int
{
Range = 2,
.../...
}
enum Parameter : int
{
ExposureTime = F(ValueType.FloatingPoint, ConstraintType.Range, 23),
.../...
}
The problem is in the signature of F if I use:
private static int F(ValueType _V, ConstraintType _C, int _N) { ... }
I get an error (invalid arguments) for every call in the definition of Parameter, but if I use the following instead:
private static int F(int _V, int _C, int _N) { ... }
Everything is fine.
It's not a blocking problem, but I'd like to understand why is that.
The C# spec states in section 14.3 ("Enum members") that
Within an enum member initializer, values of other enum members are
always treated as having the type of their underlying type, so that
casts are not necessary when referring to other enum members.
As far as I can tell this is why the arguments appear to have a type of int. It's interesting to note that this will not result in an invalid argument error:
ExposureTime = F((ValueType)ValueType.FloatingPoint,
(CostraintType)ConstraintType.Range,
23),
Of course it will still result in another error because you cannot use a method call to initialize enum members as Marc says. A method call is not a constant expression, while
The associated value of an enum member is assigned either implicitly
or explicitly. If the declaration of the enum member has a
constant-expression initializer, the value of that constant
expression, implicitly converted to the underlying type of the enum,
is the associated value of the enum member. If the declaration of the enum member has no initializer, its associated value is set implicitly [...]
For enums with explicit values, the value must be a constant expression. F(...) is not a constant expression. Regardless of whether the parameters are int or enums, you cannot assign an enum value from a function call.
Your "everything is fine" actually means:
The expression being assigned to 'blah.Parameter.ExposureTime' must be constant
The only "problem" here is that the compiler doesn't give a very elegant error message to a particular illegal scenario.
I am designing a custom attribute class.
public class MyAttr: Attribute
{
public ValueRange ValRange { get; set; }
}
Then I am attempting to assign this attribute to a property in an adjoining class:
public class Foo
{
[MyAttr(ValRange= new ValueRange())]
public string Prop { get; set; }
}
However, the compiler is complaining the following:
'ValRange' is not a valid named attribute argument because it is not a valid attribute parameter type
I also tried converting the ValueRange class to a struct in hopes that become a value type might solve the problem. Is there any way around this?
Is there any way around this?
No.
For more details I refer you to section 17.1.3 of the C# 4 specification, which I reproduce here for your convenience:
The types of positional and named parameters for an attribute class are limited to the attribute parameter types, which are:
One of the following types: bool, byte, char, double, float, int, long, sbyte, short, string, uint, ulong, ushort.
The type object.
The type System.Type.
An enum type, provided it has public accessibility and the types in which it is nested (if any) also have public accessibility.
Single-dimensional arrays of the above types.
A constructor argument or public field which does not have one of these types, cannot be used as a positional or named parameter in an attribute specification.
Remember, the point of an attribute is to at compile time add information to the metadata associated with the entity upon which you've placed the attribute. That means that all the information associated with that attribute must have a well-defined, unambiguous way to serialize it into and out of metadata. By restricting the set of legal types to a small subset of all possible types we ensure that the compiler can always emit legal metadata that the consumer can understand.
Attribute parameter values need to be resolvable at compile time (i.e constants).
See Attribute Parameter Types on MSDN:
Values passed to attributes must be known to the compiler at compile time.
If you can create a ValueRange that is a constant, you can use it.
Is there any way around this?
Yes.
You can have your attribute use a Type property and then use types that implement a defined interface, for which the code that processes that attribute would have to assume, and as such also create an implicit, but hopefully documented, requirement to its clients:
public interface IValueRange {
int Start { get; }
int End { get; }
}
public class MyAttr : Attribute {
// The used type must implement IValueRange
public Type ValueRangeType { get; set; }
}
// ....
public class Foo {
class FooValueRange : IValueRange {
public int Start { get { return 10; } }
public int End { get { return 20; } }
}
[MyAttr(ValueRangeType = typeof(FooValueRange))]
public string Prop { get; set; }
}
This is not unlike many classes in the System.ComponentModel namespace, like DesignerAttribute.
Attribute parameters must be values of the following types (quoting the article):
Simple types (bool, byte, char, short, int, long, float, and double)
string
System.Type
enums
object (The argument to an attribute parameter of type object must be a constant value of one of the above types.)
One-dimensional arrays of any of the above types
Edit: Changed "compile-time constant" to "value", since types and arrays are not constants (thanks to the commenter who pointed this out (and subsequently deleted his comment for some reason...))
Attributes can only receive compile-time-constants as parameters (e.g. 3, "hello", typeof(MyClass), "path to a resource defining whatever non constant data you need").
The last example (passing a type) I gave may help you design a workaround (pass a type implementing an interface with the method you need).
I'm currently rewriting parts of a custom RPC mechanism (which cannot be replaced by something else, so don't suggest that ;-) ). The arguments of a call are collected in a custom collection that uses a dictionary internally. There is a method T Get<T>(string) to retrieve a named argument. For optional arguments, I wanted to add a TryGet<T>(string) method that returns the argument or null if it doesn't exist, so that the calling code can provide a default value using the null coalescing operator. Of course, for a value type this doesn't work, but I could use T? instead, which is what I want.
So what I have is this:
public class Arguments
{
// lots of other code here
public T TryGet<T>(string argumentName) where T : class
{
// look up and return value or null if not found
}
public T? TryGet<T>(string argumentName) where T : struct
{
// look up and return value or null if not found
}
}
With that, I'd like to be able to do the following:
return new SomeObject(
args.TryGet<string>("Name") ?? "NoName",
args.TryGet<int>("Index") ?? 1
);
Since the constraints are mutually exclusive, the compiler should be able to produce the correct code (it's always possible to infer the call from the generic type given at the call site). The compiler complains that the type already defines a member called "TryGet" with the same parameter types.
Is there any way to make something like this work without giving the two methods different names?
Constraints are not part of the signature. thus the answer to your question is no.
The way classes in the .NET Framework handle this scenario is TryGetValue with an out parameter. The return value is an indicator of whether the get was successful, where the out parameter contains the value requested (on success) or a suitable default value (on failure).
This pattern makes the implementation very simple for reference and value types. You would only need a single method to handle both scenarios.
For an example of this pattern, see Dictionary<TKey,TValue>.TryGetValue.
The reason this doesn't work is because you cannot have two methods with the same name and same argument types (the return type is not taken into account for method overloading). Instead you could define a single method without the generic constraint which will work for both value and reference types:
public T TryGet<T>(string argumentName)
{
if (!_internalDictionary.ContainsKey(argumentName))
{
return default(T);
}
return (T)_internalDictionary[argumentName];
}
An alternative solution could be this one:
public class Arguments {
public T Get<T>(string argumentName,T defaultValue) {
// look up and return value or defaultValue if not found
}
}
return new SomeObject(
args.Get<string>("Name","NoName"),
args.Get<int>("Index",1)
);
In that particular case you would not even have to specify the generic type, as it could be inferred by the default parameter:
return new SomeObject(
args.Get("Name","NoName"),
args.Get("Index",1)
);
Although it does not work directly due to identical argument types, You can do that by adding optional defaultValue parameter which defaults to null:
public class Arguments
{
// lots of other code here
public T? TryGet<T>(string argumentName, T? defaultValue = null) where T : class
{
// look up and return value or null if not found
}
public T? TryGet<T>(string argumentName, T? defaultValue = null) where T : struct
{
// look up and return value or null if not found
}
}
The reason this one works is that second argument type is different for both contraints (In the the method with class constraint it is simply T, and in the method with struct constraint it is Nullbale<T>).
Following code works as you would expect:
var args = new Arguments();
var stringValue = args.TryGet<string>("Name") ?? "NoName";
var intValue = args.TryGet<int>("Index") ?? 1;