In Java we can use methods in enums, for example i can write
public static void main(String []args){
System.out.println(GetNum.TWO.get());
}
enum GetNum{
ONE{
public int get(){
return 1;
}
},
TWO{
public int get(){
return 2;
}
};
public abstract int get();
}
maybe somebody can say me: in c# enums can I do something like this?
Not really, but you can sort of though the use of extension methods.
Given an enumeration such as
enum HurfDurf
{
Hurr,
Durr
}
you can create an extension method such as
static class HurfDurfExtensions
{
public static string Wat(this HurfDurf lol)
{
return lol == HurfDurf.Hurr ? "Wew lad" : "eyy boss";
}
}
and use it like
var whatisthisidonteven = HurfDurf.Hurr.Wat();
No you can't. In the background enum are value-types (e.g. just an int).
E.g. you can do int i = (int)yourEnum;and vice versa.
Related
I have taken the following class from another SO question:
public class Range<T> where T : IComparable<T>
{
public T Minimum { get; set; }
public T Maximum { get; set; }
public override string ToString() { return String.Format("[{0} - {1}]", Minimum, Maximum); }
public Boolean IsValid() { return Minimum.CompareTo(Maximum) <= 0; }
public Boolean ContainsValue(T value)
{
return (Minimum.CompareTo(value) <= 0) && (value.CompareTo(Maximum) <= 0);
}
}
I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
public class Ranges<T> where T : Range<T>
{
private List<Range<T>> rangelist;
public void add(Range<T> range)
{
rangelist.Add(range);
}
public Boolean ContainsValue(T value)
{
foreach (Range<T> range in rangelist)
{
if (range.ContainsValue(value)) return true;
}
return false;
}
}
However, i am getting the error The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Range<T>'. There is no implicit reference conversion from 'T' to 'System.IComparable<T>'.
What exactly is going wrong here?
You don't seem to need the constraint where T : Range<T>
Just repeat the comparable constraint:
public class Ranges<T> where T : IComparable<T>
{
}
If you rewrite your second class slightly, you'll see why:
public class Ranges<U> where U : Range<U>
{
private List<Range<U>> rangelist;
public void add(Range<U> range)
{
rangelist.Add(range);
}
...
}
The error is telling you the compiler does not know if U is convertible to IComparable<U>, which is apparent from the declaration of Ranges<U> and Range<T> (Range<T> does not implement any interfaces).
More importantly, you have a recursing generic argument!
If U is Range<U>, then your class looks like Ranges<Range<T>> where T is U, and so on and so forth.
From what I can tell, you're not looking to write:
Ranges<Range<int>> x = ...;
But rather:
Ranges<int> x = ...;
Which would mean:
public class Ranges<T> where T : IComparable<T>
{
private List<Range<T>> rangelist;
...
You don't need new classes for that, use linq.
list1.All(x=>list2.Any(y=>y == x))
UPDATE: You are saying : I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
So effectively you have list of lists. Or more generally IEnumerable of IEnumerables.
There is enough standard generic data structures to handle this scenario
public static class ListOfListExtention {
public static bool ContainAny( this List<List<int>> lists, int number ) {
return lists.Any(l=>l.Any(x=>x == number))
}
}
Which can be rewritten in more generic way using IComparable interface
public static class ListOfListExtention {
public static bool ContainAny<T>
(this List<List<int>> lists, int value ) where T : IComparable<T> {
return lists.Any(l=>l.Any(x=>x == value))
}
}
So to compare with accepted answer, why wrap List in new class if you can just have one extension method.
How to get around? I do not want to have functions with different names.
public class DataRowSafe
{
public String Get(String Column)
{
return String.Empty;
}
public int Get(String Column)
{
return 0;
}
}
DataRowSafe r=new DataRowSafe();
String res=r.Get("Column1");
int res2=r.Get("Column2");//<--- Ambiguous call
The overloading of methods requires your similar-named methods to have different signatures. The return-value is insignificant! Have a look at this tutorial here.
You can't, there is no way, the only way would be to have a different signature.
You can you referenced parameners like this instead
public class DataRowSafe
{
public void Get(String Column, ref string myParam)
{
myParam = String.Empty;
}
public void Get(String Column,ref int myParam)
{
myParam = 0;
}
}
int i = 0;
string st = "";
new DataRowSafe().Get("name", ref i);
new DataRowSafe().Get("name", ref st);
you should be getting an error like
'DataRowSafe' already defines a member called 'Get' with the same
parameter types
The return type of the function is not significant but in this case the compiler is confused with the two method available for call and not sure which is to be picked up maybe you could use generics to overcome this
a sample like
public static T GetValue<T>(string column)
{
string returnvalue="";
//process the data ...
return (T)Convert.ChangeType(returnvalue, typeof(T), CultureInfo.InvariantCulture);
}
It is not possible, because overloading works only for different signatures. If signatures are the same then c# compiler will return error.
I have this Enum code:
enum Duration { Day, Week, Month };
Can I add a extension methods for this Enum?
According to this site:
Extension methods provide a way to write methods for existing classes in a way other people on your team might actually discover and use. Given that enums are classes like any other it shouldn’t be too surprising that you can extend them, like:
enum Duration { Day, Week, Month };
static class DurationExtensions
{
public static DateTime From(this Duration duration, DateTime dateTime)
{
switch (duration)
{
case Day: return dateTime.AddDays(1);
case Week: return dateTime.AddDays(7);
case Month: return dateTime.AddMonths(1);
default: throw new ArgumentOutOfRangeException("duration");
}
}
}
I think enums are not the best choice in general but at least this lets you centralize some of the switch/if handling and abstract them away a bit until you can do something better. Remember to check the values are in range too.
You can read more here at Microsft MSDN.
You can also add an extension method to the Enum type rather than an instance of the Enum:
/// <summary> Enum Extension Methods </summary>
/// <typeparam name="T"> type of Enum </typeparam>
public class Enum<T> where T : struct, IConvertible
{
public static int Count
{
get
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type");
return Enum.GetNames(typeof(T)).Length;
}
}
}
You can invoke the extension method above by doing:
var result = Enum<Duration>.Count;
It's not a true extension method. It only works because Enum<> is a different type than System.Enum.
Of course you can, say for example, you want to use the DescriptionAttribue on your enum values:
using System.ComponentModel;
public enum Duration
{
[Description("Eight hours")]
Day,
[Description("Five days")]
Week,
[Description("Twenty-one days")]
Month
}
Now you want to be able to do something like:
Duration duration = Duration.Week;
var description = duration.GetDescription(); // will return "Five days"
Your extension method GetDescription() can be written as follows:
using System.ComponentModel;
using System.Reflection;
public static string GetDescription(this Enum value)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
if (fieldInfo == null) return null;
var attribute = (DescriptionAttribute)fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute));
return attribute.Description;
}
All answers are great, but they are talking about adding extension method to a specific type of enum.
What if you want to add a method to all enums like returning an int of current value instead of explicit casting?
public static class EnumExtensions
{
public static int ToInt<T>(this T soure) where T : IConvertible//enum
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type");
return (int) (IConvertible) soure;
}
//ShawnFeatherly funtion (above answer) but as extention method
public static int Count<T>(this T soure) where T : IConvertible//enum
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type");
return Enum.GetNames(typeof(T)).Length;
}
}
The trick behind IConvertible is its Inheritance Hierarchy see MDSN
Thanks to ShawnFeatherly for his answer
A Simple workaround.
public static class EnumExtensions
{
public static int ToInt(this Enum payLoad) {
return ( int ) ( IConvertible ) payLoad;
}
}
int num = YourEnum.AItem.ToInt();
Console.WriteLine("num : ", num);
You can create an extension for anything, even object(although that's not considered best-practice). Understand an extension method just as a public static method. You can use whatever parameter-type you like on methods.
public static class DurationExtensions
{
public static int CalculateDistanceBetween(this Duration first, Duration last)
{
//Do something here
}
}
See MSDN.
public static class Extensions
{
public static string SomeMethod(this Duration enumValue)
{
//Do something here
return enumValue.ToString("D");
}
}
we have just made an enum extension for c# https://github.com/simonmau/enum_ext
It's just a implementation for the typesafeenum, but it works great so we made a package to share - have fun with it
public sealed class Weekday : TypeSafeNameEnum<Weekday, int>
{
public static readonly Weekday Monday = new Weekday(1, "--Monday--");
public static readonly Weekday Tuesday = new Weekday(2, "--Tuesday--");
public static readonly Weekday Wednesday = new Weekday(3, "--Wednesday--");
....
private Weekday(int id, string name) : base(id, name)
{
}
public string AppendName(string input)
{
return $"{Name} {input}";
}
}
I know the example is kind of useless, but you get the idea ;)
I'm building some stuff out using Attributes. One thing I'd really like to implement as an attribute is a convert a string to this property's type using this function. Right now, I have this:
public delegate object ParameterConverter(string val);
[AttributeUsage(AttributeTargets.Property)]
public class ParameterConverterAttribute : ParameterBaseAttribute
{
ParameterConverter Converter;
public ParameterConverterAttribute(ParameterConverter converter)
{
Converter=converter;
}
public object Convert(string val)
{
return Converter(val);
}
}
And I use it like so:
public class Tester
{
[ParameterConverter(new ParameterConverter(TestConverter)] //error here
public int Foo{get;set;}
static object TestConverter(string val)
{
return 10;
}
}
However, .Net or at least C# doesn't appear to support this kind of thing. It appears that delegates inside of attributes doesn't work.
Is there any workarounds to this issue or a good way to deal with this problem?
No Delegates cannot be passed as an argument to an Attribute. The Supported types are :
Object
Type
Enum
Single Dimentional Array
bool, byte, float char, double, int, long, string .... etc.
But as it supports Type as well as strings, you can pass a Type and the name of the method to create a delegate inside the Attribute class.
public delegate object ParameterConverter(string val);
[AttributeUsage(AttributeTargets.Property)]
public class ParameterConverterAttribute : ParameterBaseAttribute
{
public ParameterConverter Converter { get; set; }
public ParameterConverterAttribute(Type delegateType, string method)
{
try{ // Important as GetMethod can throw error exception or return null
this.Converter = (ParameterConverter)Delegate.CreateDelegate(delegateType, delegateType.GetMethod(method));
}
catch { }
}
public object Convert(string val)
{
if(this.Converter != null)
return Converter(val);
}
}
And now you can use it like :
public class Tester
{
[ParameterConverter(typeof(ParameterConverter), "TestConverter"]
public int Foo{get;set;}
static object TestConverter(string val)
{
return 10;
}
}
I hope this would help you.
Lookup for TypeConverter class
or
Type Converter Example
This example shows how to create a type converter named AuthorConverter....The AuthorConverter example converts an Author object to a String and a String representation to an Author object.
UPDATE:
You can skip the limitations of attributes like #abhishek has shown.
Possible another way is to define some "convention over configuration": converter function is a method defined like so
private static Converter(string val) defined inside same class. In your case:
public class Tester
{
public int Foo{get;set;}
private static int FooConverter(string val)
{
return 10;
}
}
You can put some ParameterConverterAttribute on top of the property as a sign that custom converter function exists, but is not mandatory.
I have the following class and extension class (for this example):
public class Person<T>
{
public T Value { get; set; }
}
public static class PersonExt
{
public static void Process<TResult>(this Person<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
I was expecting I could write something like the following and it would work, but it doesn't:
var x = new Person<List<String>>();
x.Process();
Since List is lower in the inheritance tree than IEnumerable, shouldn't this be valid? It works if I new up a Person<IEnumerable<String>> of course because that's the direct type.
I'm trying to use an extension method that can be applied to all Person<T>'s as long as T implements IEnumerable<Something> because I need to use the .Any() method.
EDIT: Maybe my understanding of covariance is off? I know IEnumerable<String> should convert to IEnumerable<Object>, but couldn't IList<String> convert to IEnumerable<String>?
EDIT2: Forgot to mention that I am using .net 4.0.
I know IEnumerable<String> should
convert to IEnumerable<Object>, but
couldn't IList<String> convert to
IEnumerable<String>?
IList<String> can convert to IEnumerable<String>. The problem is that you're trying to convert Person<List<String>> to Person<IEnumerable<String>>, which is illegal. For example, it's perfectly valid to write:
var x = new Person<IEnumerable<String>>();
x.Value = new string[0];
since Value is of type IEnumerable<String> and a string array is an IEnumerable<String>. However, you cannot write:
var x = new Person<List<String>>();
x.Value = new string[0];
since Value is of type List<String>. Since you can't use a Person<List<String>> in all places where you could use a Person<IEnumerable<String>>, it's not a legal cast.
Note that you can do something similar to what you want if you add a second type parameter to your extension method:
public static void Process<TResult, TList>(this Person<TList> p)
where TList : IEnumerable<TResult>
{
Console.WriteLine(p.Value.Any());
}
Unfortunately, the compiler won't be able to infer both type parameters, so you would have to call it like this:
var x = new Person<List<String>>();
x.Process<String, List<String>>();
If you are using C# 4.0 and can use covariance, then you can define a covariant interface for person:
public interface IPerson<out T>
{
T Value { get; }
}
public class Person<T>
: IPerson<T>
{
public T Value { get; set; }
}
And then write your extension method as:
public static void Process<TResult>(this IPerson<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
Since IPerson<T>.Value is read-only, a IPerson<List<String>> can be used everywhere that an IPerson<IEnumerable<String>> can be, and the conversion is valid.
I'm not sure you've quite grasped the correct use of generics. In any event ...
The only thing that is incorrect is your declaration of extension method, and the way you are attempting to constrain the extension method.
public static class ThingExtensions
{
public static void Process<T>(this Thing<T> p)
where T : IEnumerable<string>
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
All I've really done is rename Person to Thing so that we're not getting hung up on what a Person<List<string>> really is.
public class Thing<T>
{
public T Value { get; set; }
}
class ListOfString : List<string>
{ }
class Program
{
static void Main(string[] args)
{
var x = new Thing<ListOfString>();
x.Value = new ListOfString();
x.Process();
x.Value.Add("asd");
x.Process();
var x2 = new Thing<int>();
// Error 1 The type 'int' cannot be used as type parameter 'T'
// in the generic type or method
// 'ThingExtensions.Process<T>(Thing<T>)'.
// There is no boxing conversion from 'int' to
// 'System.Collections.Generic.IEnumerable<string>'.
//x2.Process();
Console.Read();
}
}
You could also move the generic constraint to the Thing<T> if that was more applicable.
You mention covariance, but don't actually use it. You have to specify in or out on your generic parameters. Note that co/contravariance doesn't work on class types; they must be applied to interfaces.
So, introducing an interface and making it covariant:
public interface IPerson<out T>
{
T Value { get; }
}
public class Person<T> : IPerson<T>
{
public T Value { get; set; }
}
public static class PersonExt
{
public static void Process<TResult>(this IPerson<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
allows this code to compile:
var x = new Person<List<String>>();
x.Process();