Domanda

I'm returning values from an Entity object. Some of them are String typed and some are not. Right now, I did a quick solution as follows.

private String GetStringValue(Entity entity, String attribute, String substitute = "")
{
  if(entity.Contains(attribute)
    return entity[attribute] as String;
  return substitute;
}

private String GetIntValue(Entity entity, String attribute, int substitute = 0)
{
  if(entity.Contains(attribute)
    return entity[attribute] as int;
  return substitute;
}

Then I remembered that there's a syntax for generic typing (something like <TypeX>). My question is, however, if there's a point to start changing the existing code. I'll need to change the signature of the method in two places (return type and substitute type) but I fear that I'll need to do some complex coding inside the method as well.

On the other hand, I'd have a nice way to treat all the types possible (and I have a hunch we'll be working with more than strings and integers.

È stato utile?

Soluzione 2

You are right "something like" is the generic method. Check out generic methods there. Next method looks good for your purpose.

   private  static T GetValue<T>(Entity entity, string attribute, T defaultValue)
        {
            if (!entity.Contains(attribute))
                return defaultValue;

            return  (T)entity[attribute];
        }

EDIT: updated according of the w0lf's comment.

Altri suggerimenti

You will have to change the signature of the method in three places, because you also have to add the generic parameter:

private T GetValue<T>(Entity entity, String attribute, T substitute)

Within the method, there's no real need for any complex coding; replacing your current occurrences of string or int, respectively, with T, should suffice. (Note that the as operator can only be applied if you restrict T to reference types - which you probably don't want to do, because int is a value type).

Note that there are two issues with this method that you might consider drawbacks:

  • This generic method will support "all the types possible", but it will also support any types impossible (users are free to specify whatever type they like for T, and there is no way to restrict T while still supporting both string and int.
  • You cannot specify arbitrary default substitute values for each type. What you can do is declare a default value for substitute, namely default(T), but at least for string, that is not an empty string, but null.

If you don't want to change method signature, you can write a generic function and call it from all of these non generic versions.

private String GetStringValue(...){
    return GetValue<String>(...);
}

By the way, you are looking for Generic methods

For e.g (from msdn)

static void Swap<T>(ref T lhs, ref T rhs)
{
    T temp;
    temp = lhs;
    lhs = rhs;
    rhs = temp;
}

...

Swap<int>(ref a, ref b);

or just

Swap(ref a, ref b); //type int is infered based on type of arguements and method signature

What class is Entity? Assuming it's a custom class, make it also generic, then this works:

private T Get<T>(Entity<T> entity, T attribute, T substitute = default(T))
{
    if (entity.Contains(attribute))
        return entity[attribute];
    return substitute;
}

You can retrieve the value in this way:

var entity = new Entity<string>();
string val = Get<string>(entity, "attr", "subst");

You should define your Entity<T> class:

public class Entity<T>
{
    // TODO: implement
    public T this[string i] { get; set; }

    // TODO: implement
    internal bool Contains(string attribute)
    {
        return true;
    }
    // TODO: implement
    // other properties and methods       
}

And you may use a generic method:

private T GetStringValue<T>(Entity<T> entity, String attribute, T substitute = default(T))
{
    if (entity.Contains(attribute))
        return entity[attribute];
    return substitute;
}

If it is possible to generalize the code inside a method I would absolutely recommend to use it in a generic way. It makes the class smaller, better readable and you just have to change one method if requirements change. Your method looks like it can be made generic easily.

private T GetIntValue<T>(Entity entity, String attribute, T substitute = default(T))
{
    if(entity.Contains(attribute))
        return (T)entity[attribute];
    return substitute;
}

If there would be some more logic to execute you could also use a dictionary with functions for the different types:

private IDictionary<Type, Func<Entity, string, object>> actions;

private void InitActions()
{
    actions = new Dictionary<Type, Func<Entity, string, object>>
        {
            {
                typeof (string), (entity, attribute) =>
                    {
                        // this could be your custom code for string
                        return entity[attribute];
                    }
            },
            {
                typeof (int), (entity, attribute) =>
                    {
                        // this could be your custom code for int
                        return entity[attribute];
                    }
            }
        };
}

private T GetIntValue<T>(Entity entity, String attribute, T substitute = default(T))
{
    if (entity.Contains(attribute) && actions.ContainsKey(typeof (T)))
    {
        Func<Entity, string, object> action = actions[typeof (T)];
        return (T)action(entity, attribute);
    }
    return substitute;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top