3

I have 3 classes, all share similar properties. 3 of the properties are named exactly the same across all 3 classes. Rather that write 3 methods (one for each class) is there some way I can utilise generics here?

public static String GetAString(ActivityMedia activityMedia)
{
   return activityMedia.name;
}

public static String GetAString(AuditMedia auditMedia)
{
   return auditMedia.name;
}

public static String GetAString(VehicleMedia vehicleMedia)
{
   return vehicleMedia.name;
}

EDIT: Obviously with the aim of simply passing an object of one of those 3 class types to GetAString()

10 Answers10

4
  1. introduce interface with a single string Name property
  2. mark all three classes by interface
  3. Now you can assess media Name directly I've no idea why you need a method for this but anyway, you can create extension method for the interface type IMedia
interface IMedia
{
    string Name { get; }
}

class ActivityMedia : IMedia
class AuditMedia : IMedia
class VehicleMedia : IMedia

static class MediaExtensions
{
   public static string GetName(this IMedia instance)
   {
          return instance.Name;
   }
}
sll
  • 61,540
  • 22
  • 104
  • 156
  • Don't you think its redundant to implement Name property on all ActivityMedia, AuditMedia, VehicleMedia classes if you use interface? Although interface has different purpose – Abdul Munim Nov 24 '11 at 12:41
  • You do not need implement it because all three media already has Name property, thi is let's say marker interface – sll Nov 24 '11 at 12:43
  • Its duplicate, isn't it? What you say? – Abdul Munim Nov 24 '11 at 12:46
3

If they are completely unrelated, one option is to use dynamic (if you're on C# 4):

public static String GetAString(dynamic d){
    return d.name;
}

Edit:

If you're not using C# 4.0, you can use reflection:

public static string GetAString(object o)
{
    System.Reflection.PropertyInfo name = o.GetType().GetProperty("name");
    return (string) name.GetValue(o, null);
} 
Vlad
  • 18,195
  • 4
  • 41
  • 71
  • We're not on 4 yet unfortunately. That looks like the perfect solution if we were though. I'm going to look into that. –  Nov 24 '11 at 12:32
  • Where is .NET 4 was mentioned? – sll Nov 24 '11 at 12:32
  • Alternatively, you can use reflection. – Vlad Nov 24 '11 at 12:35
  • 1
    I don't understand where this discussion is going!? Vlad has suggested a solution for if I were coding in C# 4, that's all. –  Nov 24 '11 at 12:35
  • @ChrisBD : obviously you come here a bti later so was not able to see original answer without specifying `if .NET 4...` – sll Nov 24 '11 at 12:44
  • I guess, this question more on design issue rather than implementation – Abdul Munim Nov 24 '11 at 12:47
  • It's a design issue only if the OP has access to the source code of their 3 classes and there are no restrictions on changing them. – Vlad Nov 24 '11 at 12:49
3

Another option is to use an interface...

public interface INameable
{
   String Name { get; }
}

public static String GetAString(INameable nameable)
{
   return nameable.Name;
}

Although at this point you probably don't even need the GetAString method?

Ian
  • 33,605
  • 26
  • 118
  • 198
3

You could do this with an interface

public interface INamedMedia
{
    string Name { get; }
}

then your method becomes

public static String GetAString(INamedMedia media)
{
    return media.Name;
}

and your classes implement INamedMedia

public class Media : INamedMedia
{
    public string Name { get { return "Media"; } }
}
Russ Cam
  • 124,184
  • 33
  • 204
  • 266
3

I would have thought that an interface would be the ideal solutions here:

public interface IMedia
{
    public String Name { get; }
}

and then you could have your static method taking that interface type as it's parameter:

    public static String GetAString(IMedia media)
    {
        return media.Name;
    }

Or all of your media classes could derive from a base type which contains the property you require and pass that into the method instead of the interface.

It's difficult to tell you which is the better option because it depends on the complexity of your application and the inheritance chain already.

This article may be of help

Paulie Waulie
  • 1,690
  • 13
  • 23
2

you do not need generics, you need OOP and inheritance.

Make ActivityMedia, AuditMedia and VehicleMedia all to either implement a base interface like IMedia or derive a basic class like MediaBase

then you write the method GetAString only once which accepts either an IMedia object or a MediaBase object.

another option could be that you override the default ToString method in ActivityMedia, AuditMedia and VehicleMedia so to just return the name property then you will just call ToString without the need of any GetAString method.

Davide Piras
  • 43,984
  • 10
  • 98
  • 147
2

Generics won't help you here if these classes share no common ancestry. The solution is to arrange that they do share common ancestry by declaring an interface with a name property. Make each class implement that interface and then you can have a single GetAString function.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
2

If the three classes have a sub set of the same properties your better off implementing a base class instead with the common properties and methods declared in the base class which the three media classes are derived from.

public class ActivityMedia : Media 
{

}

public class Media
{
     public string Name {get;set;}
}

This way the three classes have one set of methods defined in one place making the code much easier to maintain. while giving you the flexibility to put class specific methods in their derived implementation.

Chris
  • 3,114
  • 1
  • 18
  • 27
2

It's more logical to implement inheritance here rather than generics.

You can also use Interface but that would make your Name property duplicate on all your ActivityMedia, AuditMedia, VehicleMedia classes.

Consider a base class Media

public class Media
{
    // consider all properties that are common
    // on Media domain
    public string Name { get; set }
}

And inherit ActivityMedia, AuditMedia, VehicleMedia from Media class.

public class ActivityMedia : Media
{
    // other properties on ActivityMedia domain
}

public class AuditMedia : Media
{
    // other properties on AuditMedia domain
}

public class VehicleMedia : Media
{
    // other properties on VehicleMedia domain
}

And now use Media class on your GetAString method

public static String GetAString(Media activityMedia)
{
   return activityMedia.name;
}

public static String GetAString(Media auditMedia)
{
   return auditMedia.name;
}

public static String GetAString(Media vehicleMedia)
{
   return vehicleMedia.name;
}
Abdul Munim
  • 18,869
  • 8
  • 52
  • 61
  • 1
    Inheritance sometimes a devil, and when you want to share single property across three classes it would be a bad idea to do it via base class (moreover not abstract) – sll Nov 24 '11 at 14:34
1

This is where inheritance comes to your rescue. Have such base class:

public class Media
{
    public string name { get { return "Media"; } }
}

Then each class will inherit and define its own name:

public class ActivityMedia : Media
{
    public new string name { get { return "Activity Media"; } }
}

And finally:

public static String GetAString(Media media)
{
    return media.name;
}

Edit: as you're stuck with your current design, you can use reflection:

public static String GetAString(object media)
{
    PropertyInfo propName = media.GetType().GetProperty("name");
    if (propName != null)
        return propName.GetValue(media, null);
    return "";
}
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • It would not be my decision to re-design these classes to inherit from a media class though. I'm pretty much stuck with working with the separate classes for now. I see what you mean though and I take it on board as an otherwise spot on answer. –  Nov 24 '11 at 12:34
  • See my edit, it will just look for property called "name" and get its value no matter what the object type is. – Shadow The GPT Wizard Nov 24 '11 at 12:38