0

Hi there I have looked and need some help, I am using reflections to get values from a class, The classes have a similar property called "Name" I have a method

public static void GetName<T>(T Object)
{
    xxxxxxx
}

Now the user will use this method with someting like so

var User = .....
var name = GetName(User);

How can I restrict usage to a class object only, as I want to prevent List and other types from being use ex

List<SystemUsers> users = ..... 
var name = GetName(users) ... this should not be allowable

Is there such a way, I tried placing "class" and "where T : new()"

But it does not seem it is doing the trick

Please Help

6
  • you can't do this at compile time. a list is a reference type. Commented Apr 10, 2015 at 19:39
  • 4
    you could add an interface IHaveName. Commented Apr 10, 2015 at 19:40
  • Hi Daniel Please explain, I have never used Interfaces to the generic extend. Please explain Commented Apr 10, 2015 at 19:43
  • If you can add to the GetName method you can add a type test to the begging: if (T.GetType().Equals(typeof(List))) { throw new InvalidOperationsException(); }; Commented Apr 10, 2015 at 19:43
  • 1
    GetName has a return type of void...are we all looking at the same thing? Commented Apr 10, 2015 at 19:46

4 Answers 4

1

In your GetName() method, you will need to test the object type, and throw an exception if it is not a valid type.

However, this really isn't an efficient way of doing this. You might be better using an interface instead, so that you won't need to worry with what types you don't allow--since the number of invalid types could reach infinite limits.

Sign up to request clarification or add additional context in comments.

3 Comments

HI Russ, Please can you explain the Interface part as I have not used it and not sure how to implement it in such a generic method
You might best understand by following a tutorial: csharp-station.com/Tutorial/CSharp/lesson13
Thanks Russ, I am looking at that link now.
1

As Daniel has stated in the comment to the original question, having each object implement an interface which contains the property and have your method take that interface as its parameter would be the best way to restrict it, for example:

public static void GetName(IPerson entity) { entity.Name = "Test"; }

4 Comments

HI Steve can you please explain or give me a small sample so I can see how to do it. as i have not used interfaces with generics before.
Yes, sorry! I was already in the process of editing my answer with a quick example. Hope that helps!
Thanks Steve, mmmm. It could work, I just have to check if this part will work on a interface not sure var propertyList = Object.GetType().GetProperties();
Thanks Steve you are a star! Its working like a charm. thank you thank you.
1

Just to throw another option out there, since you're already using reflection, you could also use it on the passed-in object to detect if it has a name property.

This won't give any compile-time exceptions, however, so you'd have to try/catch when calling it or have it return an empty string instead of throw an exception (or something else...).

For example, if you only want objects that have a Name property, you could do something like:

private static string GetName<T>(T input)
{
    var nameProperty =
        typeof (T)
            .GetProperties()
            .FirstOrDefault(propInfo =>
                propInfo.Name.Equals("Name", StringComparison.OrdinalIgnoreCase));

    if (nameProperty == null)
    {
        throw new InvalidOperationException(
            "The input type does not have a name property");
    }

    return (string) nameProperty.GetValue(input);
}

1 Comment

Thanks Rufus, Interesting, I have another peace that i will look into your technique. I am building a library of examples and would love to share it when I am done,
0

You can't. As mentioned in comments, List<> is a class. Restricting it to classes will include it.

This is an unfortunate case where you'll probably have to simply rely on the contract being used by calling code, and throw an exception for invalid arguments.

public static string GetName<T>(T Object)
{
    if(Object is IEnumerable) throw new ArgumentException();
    xxxxxxx
}

Another option might be to add an overload that takes an IEnumerable. It's not super pretty, and you might not need it, but at least then the compiler will choose that and return something appropriate.

public static IEnumerable<string> GetName<T>(IEnumerable<T> Objects)
{
    return Objects.Select(GetName);
}

Be careful with this, though, because it can sometimes be difficult to predict (or rather, to remember to predict) which one will be called.

List<int> ints = new List<int>();

GetName(ints); // calls the IEnumerable version

object intsObj = (object)ints;
GetName(intsObj); // calls the non-IEnumerable version.

More generally speaking, though, it sounds like you might be setting up a less-than-ideal contract here. If you're doing something like this with unfiltered generics, you'll probably want to be able to handle collections in it as well, and indeed I'm not sure why you wouldn't be able to. They're objects just like anything else.

If you are trying to restrict it, you'll probably want an interface or base class from which all objects passed to this method must be inherited. That will significantly cut down your options for passing .NET classes in, but I can't imagine what use those would have anyway, if you need to get a "name" from something.

If you go that route, you have two options:

  • Restrict the parameter itself
  • Restrict the generic argument

The choice there depends on the contents and return type of the method, but I'd probably go with the former.

public static string GetName<T>(IObjectWithName Object)
{
    return Object.Name;
}

That's not particularly interesting as an example, though, so here's how you would restrict the generics.

public static string GetName<T>(T Object)
    where T : IObjectWithName
{
    return Object.Name;
}

Just remember that your object needs to implement that interface--you can't pass a DateTime, for instance, to this method and expect it to work. If you expect "random" input like that, you'll probably need to set yourself up to receive collection types as well.


I should mention, just for good practice, that naming your parameters Object is not a good habit. That's a keyword (or rather, a System-level type) in C#. So you could wind up with conflicts.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.