C # method capable of handling / accepting different types of classes

I have a method that takes a simple class object and builds the URL used in the API call. I would like this method to be able to handle / accept different types of classes that are similar but have different properties.

public class ClientData
{
   public string Name {get; set;}
   public string Email {get; set;}
   ...
}

public class PaymentData
{
   public decimal PaymentAmount {get; set;}
   public string Description {get; set;}
   ...
}

The following are two examples. As you can see, they are very similar. Would it be better to implement them as different methods that take different parameters, or can you write one method that can deal with differences in parameter objects?

public string BuildApiCall(ClientData clientDataObject)
{
  StringBuilder sb = new StringBuilder();
  sb.Append("http://mytestapi.com/");
  sb.append("name=" + clientDataObject.Name);
  sb.append("email=" + clientDataObject.Email);
  return sb.ToString();
}

public string BuildApiCall(PaymentData paymentDataObject)
{
  StringBuilder sb = new StringBuilder();
  sb.Append("http://mytestapi.com/");
  sb.append("payment=" + paymentDataObject.PaymentAmount );
  sb.append("description=" + paymentDataObject.Description );
  return sb.ToString();
}
+4
source share
2 answers

Determining which approach to take

Your problem is to create your own serializer for your classes based on the provided API (supposedly fixed).

, , ( ) POCOs DTO, . , , XmlSerializer DataContractSerializer XML Protobuf.NET , , .

, , , , . , / , , . , " ", , , , ( ).

-

, , , . , :

public class ClientData
{
    public string Name { get; set; }
    public string Email { get; set; }
}

a XmlSerializer - XML:

<ClientData>
    <Name>...</Name>
    <Email>...</Email>
</ClientData>

, ?name=...&email=... , - . , , , API.

, API, , , , API, ( ), , .

public class ClientData
{
    public string Name {get; set;}
    public string Email {get; set;}
}

// customer really insisted that the property is
// named `PaymentAmount` as opposed to simply `Amount`,
// so we'll add a custom attribute here
public class PaymentData
{
    [MyApiName("payment")]
    public decimal PaymentAmount {get; set;}
    public string Description {get; set;}
}

MyApiName , :

public class MyApiNameAttribute : Attribute
{
    private readonly string _name;
    public string Name
    { get { return _name; } }

    public MyApiNameAttribute(string name)
    { _name = name; }
}

:

public static string Serialize(object obj)
{
    var sb = new StringBuilder();

    foreach (var p in obj.GetType().GetProperties())
    {
        // default key name is the lowercase property name
        var key = p.Name.ToLowerInvariant();

        // we need to UrlEncode all values passed to an url
        var value = Uri.EscapeDataString(p.GetValue(obj, null).ToString());

        // if custom attribute is specified, use that value instead
        var attr = p
            .GetCustomAttributes(typeof(MyApiNameAttribute), false)
            .FirstOrDefault() as MyApiNameAttribute;

        if (attr != null)
            key = attr.Name;

        sb.AppendFormat(
            System.Globalization.CultureInfo.InvariantCulture,
            "{0}={1}&",
            key, value);
    }

    // trim trailing ampersand
    if (sb.Length > 0 && sb[sb.Length - 1] == '&')
        sb.Length--;

    return sb.ToString();
}

:

var payment = new PaymentData()
{
    Description = "some stuff",
    PaymentAmount = 50.0m 
};

// this will produce "payment=50.0&description=some%20stuff"            
var query = MyApiSerializer.Serialize(payment)

, . . , (, 10 ) HTTP-, , .

, , , , , , , . ; .

+7

:

public interface IWhatsit
{
     string ToApiString();
}

. ToApiString :

public class ClientData : IWhatsit
{
   public string Name {get; set;}
   public string Email {get; set;}
   ...

   public string ToApiString()
   {
       // Do whatever you need here - use a string builder if you want
       return string.Format("Name={0}&Email={1}",Name,Email);
   }
}

API:

public string BuildApiCall(IWhatsit thing)
{
  StringBuilder sb = new StringBuilder();
  sb.Append("http://mytestapi.com/");
  sb.append(thing.ToApiString());
  return sb.ToString();
}

. , , .

, . - :

public abstract class BaseData
{
    protected abstract string ToApiString();

    public string BuildApiCall()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("http://mytestapi.com/");
        sb.append(ToApiString());
        return sb.ToString();
    }
}

:

public class ClientData : BaseData
{
   public string Name {get; set;}
   public string Email {get; set;}
   ...

   protected override string ToApiString()
   {
       // Do whatever you need here - use a string builder if you want
       return string.Format("Name={0}&Email={1}",Name,Email);
   }
}

BuildApiCall . , BuildApiCall , . BaseData, ToApiString , .

+4

All Articles