Call different functions as getter - c#

I have following class:
public class ContentVideoType
{
public string Title { get; set; }
public string GetThumbnail { get; set; }
}
When creating an instance of this class, I want to assign a custom getter for GetThumbnail. I don't know how it is called but as far as I know the code must be like:
var youtube = new ContentVideoType
{
Title = "Youtube",
GetThumbnail = (x) => { return $"https://i.ytimg.com/vi/{x}/mqdefault.jpg"; }
};
var vimeo = new ContentVideoType
{
Title = "Vimeo",
GetThumbnail = (x) => GetVimeoImage(x)
};
For Viemo for example I need to call following function for GetThumbnail:
public static string GetVimeoImage(string vimeoId)
{
string result = String.Empty;
try
{
XmlDocument doc = new XmlDocument();
doc.Load("http://vimeo.com/api/v2/video/" + vimeoId + ".xml");
XmlElement root = doc.DocumentElement;
result = root.FirstChild.SelectSingleNode("thumbnail_medium").ChildNodes[0].Value;
}
catch
{
//cat with cheese on it's face fail
}
return result;
}

I suppose, that you want to achieve inheritance in some odd way :) You should really use proper inheritance here (GetThumbnail should be method if it is receiving a string as a parameter):
public abstract class ContentVideoType
{
public virtual string Title { get; set; }
public virtual string GetThumbnail(string id)
{
return "Some Default Thumbnail";
}
}
public class YouTubeContentVideType : ContentVideoType
{
public override string GetThumbnail(string id)
{
return "";//your logic for youTube
}
}
public class VimeoContentVideType : ContentVideoType
{
public override string GetThumbnail(string id)
{
return "";//your logic for vimeo
}
}
=== UPDATE ===
Basing on your latest response - here is how it would look :
void Main()
{
foreach (var videoType in GetAll)
{
Console.WriteLine(videoType.Title + " " + videoType.GetThumbnail("1")));
}
}
public abstract class ContentVideoType
{
public virtual string Title { get; }
public virtual string GetThumbnail(string id)
{
return "Some Default Thumbnail";
}
}
public class YouTubeContentVideoType : ContentVideoType
{
public override string Title { get; } = "Youtube";
public override string GetThumbnail(string id)
{
return $"https://i.ytimg.com/vi/{id}/mqdefault.jpg";
}
}
public class VimeoContentVideType : ContentVideoType
{
public override string Title { get; } = "Vimeo";
public override string GetThumbnail(string id)
{
return GetVimeoPreview(id);
}
public string GetVimeoPreview(string videoId)
{
return $"url:{videoId}"; //your code here;
}
}
public static List<ContentVideoType> GetAll
{
get
{
var result = new List<ContentVideoType>
{
new YouTubeContentVideoType(),
new VimeoContentVideType()
};
return result;
}
}

It sounds like you want GetThumbnail to be a method that returns a string, not just a string. You can re-declare this way in order to do that:
public Func<string, string> GetThumbnail { get; set; }
That would cause this code to compile:
var youtube = new ContentVideoType
{
Title = "Youtube",
GetThumbnail = (x) => {
return string.Format("https://i.ytimg.com/vi/{0}/mqdefault.jpg", x); }
};
Note that the GetThumbnail above only accepts a method that takes one argument and returns a string.
Edit: Here's an example of how to use this:
string thumbnail = youtube.GetThumbnail("abc");

Could you create two sub-classes to ContentVideoType and each one implementing their own version of GetThumbnail?
Otherwise, the fact of being able to swap getters with reflection seems impossible: https://stackoverflow.com/a/6835824/2525304

Ok, here is how I did it with a little help and guessing :)
public class ContentVideoType
{
public string Title { get; set; }
public Func<string, string> GetThumbnail { get; set; }
}
public static List<ContentVideoType> GetAll
{
get
{
var result = new List<ContentVideoType> {
new ContentVideoType
{
Title = "Youtube",
GetThumbnail = videoId => $"https://i.ytimg.com/vi/{videoId}/mqdefault.jpg"
},
new ContentVideoType
{
Title = "Vimeo",
GetThumbnail = videoId => GetVimeoPreview(videoId)
}
};
return result;
}
}

Related

How to return string value depending on type of generic

I have this code to get a list of Star Wars API objects:
public static async Task<IList<T>> Get<T>()
where T : SWAPIEntity
{
var entities = new List<T>();
var rootUrl = (string)typeof(T).GetProperty("rootUrl").GetValue(null);
var url = $"{baseUrl}/{rootUrl}";
var result = await GetResult<T>(url);
entities.AddRange(result.results);
while (result.next != null)
{
result = await GetResult<T>(result.next);
entities.AddRange(result.results);
}
return entities;
}
Where I want rootUrl to depend on which type of SWAPIEntity is being passed in for T.
The code above throws
"Non-static method requires a target."
Where SWAPIEntity:
public class SWAPIEntity
{
public string name { get; }
}
and SWAPIEntity:
public class SWAPIEntity
{
public string name { get; }
}
and Planet:
public class Planet : SWAPIEntity
{
public string rootUrl { get; } = "planets";
public string climate { get; set; }
}
And I call it with
await StarWarsApi.Get<Planet>();
How can I get the value of rootUrl depending on which type of SWAPIEntity I am trying to get?
The error says it all.
You are trying to call a non-static member, so you need to pass an Instance. I guess the simple solution for you is to make this property static.
public class Planet : SWAPIEntity
{
public static string rootUrl { get; } = "planets";
// Or newer simpler syntax:
// public static string rootUrl => "planets";
public string climate { get; set; }
}

Missing parameterless constructor when casting Jil dynamic deserialized object array

In our application we have a problem using a dynamic object, that is the result of JSON deserialization with Jil. The following code is just to show the problem.
void Main()
{
var modelJson = "{\"Id\":1,\"Options\":[{\"Id\":2,\"Name\":\"Option 1\"}]}";
var modelDto = Jil.JSON.DeserializeDynamic(modelJson);
var options = modelDto.Options;
var optionsIEnumerable = (IEnumerable<Option>)options;
var optionsArray1 = optionsIEnumerable.ToArray();
var optionsArray2 = optionsIEnumerable.Cast<Option>().ToArray();
}
class Model
{
public Model(long id, IEnumerable<Option> options = null)
: this()
{
this.Id = id;
this.Options = options;
}
private Model() => this.Options = new List<Option>();
public long Id { get; }
public IEnumerable<Option> Options { get; }
}
class Option
{
public Option(long id, string name)
{
this.Id = id;
this.Name = name;
}
private Option()
{
}
public long Id { get; private set; }
public string Name { get; private set; }
}
The last two lines in Main both cause a MissingMethodException, saying there is no parameterless constructor. But both Model and Option have a parameterless constructor (and I am not even using Model at this point).
How can I cast the property modelDto.Options into a Option[]?
This is not the exact answer to your question but you could easily deserialize this JSON with the model.
static void Main(string[] args)
{
var modelJson = "{\"Id\":1,\"Options\":[{\"Id\":2,\"Name\":\"Option 1\"}]}";
var modelDto = Jil.JSON.Deserialize<ModelNew>(modelJson);
ShowObject(modelDto);
Console.Read();
}
class ModelNew
{
public int Id { get; set; }
public Option[] Options { get; set; }
public ModelNew() {}
}
class Option
{
public long Id { get; private set; }
public string Name { get; private set; }
private Option() {}
}
Edit:
To see the object use this function:
static void ShowObject(ModelNew obj)
{
Console.WriteLine("Id: " + obj.Id);
foreach (var op in obj.Options)
{
Console.WriteLine("Id: " + op.Id);
Console.WriteLine("Name: " + op.Name);
}
}
Output:
Id: 1
Id: 2
Name: Option 1

C# Accessing custom attribute of owner object

How can I access the custom attribute of the parent or owner object.
Look at the FieldInfo property of the SQLFieldInfo struct
Here's a more detailed program that will compile and run that shows what I need.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Employee myclass = new Employee();
// Load from sql server...
myclass.Name = "Alain";
myclass.Age = 51;
//----
MessageBox.Show(myclass.Name.ToString()); // Should return Alain
MessageBox.Show(myclass.Age.FieldInfo.Type.ToString()); // Should output "int"
}
}
// This next class is generated by a helper exe that reads SQL table design and create the class from it
[SQLTableAttribute(DatabaseName = "Employees", Schema = "dbo", TableName = "Employees")]
public class Employee
{
[SQLFieldAttribute(FieldName = "ID", Type = SqlDbType.Int)]
public SQLFieldInfo<int> ID { get; set; }
[SQLFieldAttribute(FieldName = "Name", Type = SqlDbType.NVarChar, Size = 200)]
public SQLFieldInfo<String> Name { get; set; }
[SQLFieldAttribute(FieldName = "Age", Type = SqlDbType.Int)]
public SQLFieldInfo<int> Age { get; set; }
}
public struct SQLFieldInfo<T>
{
private readonly T value;
public SQLFieldInfo(T Value)
{
this.value = Value;
}
public static implicit operator SQLFieldInfo<T>(T Value)
{
return new SQLFieldInfo<T>(Value);
}
public T Value
{
get
{
return this.value;
}
}
public override string ToString()
{
return this.value.ToString();
}
public SQLFieldAttribute FieldInfo
{
get
{
// Need to retreive the attribute class of the parent or declaring member
return null;
}
}
}
// Holds the sql field information
public class SQLFieldAttribute : Attribute
{
public string FieldName { get; set; }
public SqlDbType Type { get; set; }
public bool AllowNull { get; set; }
public int Size { get; set; }
}
// Holds the sql table information
public class SQLTableAttribute : Attribute
{
public string DatabaseName { get; set; }
public string Schema { get; set; } = "dbo";
public string TableName { get; set; }
}
Thank you!
Alain
My data class is as follows (should be fairly translatable to A above):
public class Foo
{
[Argument(Help = "Name", AssignmentDelimiter = "=")]
public string Name
{
get;
set;
}
}
A helper class is responsible of reading attribute values of objects:
static public string GetCommandLineDelimiter<T>(Expression<Func<T>> property)
{
if(property != null)
{
var memberExpression = (MemberExpression)property.Body;
string propertyName = memberExpression.Member.Name;
PropertyInfo prop = typeof(Arguments).GetProperty(propertyName);
if(prop != null)
{
object[] dbFieldAtts = prop.GetCustomAttributes(typeof(ArgumentAttribute), true);
if(dbFieldAtts.Length > 0)
{
return ((ArgumentAttribute)dbFieldAtts[0]).AssignmentDelimiter;
}
}
}
return null;
}
To use it, simply:
string delimiter = GetCommandLineDelimiter(() => myObject.Name);
That will get the attribute value of AssignmentDelimiter on property Name, i.e. "=".
First, MSDN is your friend.
Then, if you want to get the attributes for ancestors just specify true in the inherit flag of the method:
var attribute = typeof(A).GetProperty("myprop").GetCustomAttributes(true)
.OfType<MycustomAttrib>().FirstOrDefault();
This works. I am doing a lazy initialization of a reference to the custom attribute by using reflection to look at all the properties of all the types.
public class MycustomAttribAttribute : Attribute
{
public MycustomAttribAttribute(string name)
{
this.Name=name;
}
public string Name { get; private set; }
}
class A
{
public A() { MyProp=new B(); }
[MycustomAttrib(name: "OK")]
public B MyProp { get; set; }
}
class B
{
private static Lazy<MycustomAttribAttribute> att = new Lazy<MycustomAttribAttribute>(() =>
{
var types = System.Reflection.Assembly.GetExecutingAssembly().DefinedTypes;
foreach(var item in types)
{
foreach(var prop in item.DeclaredProperties)
{
var attr = prop.GetCustomAttributes(typeof(MycustomAttribAttribute), false);
if(attr.Length>0)
{
return attr[0] as MycustomAttribAttribute;
}
}
}
return null;
});
public string MyProp2
{
get
{
return att.Value.Name;
}
}
}
class Program
{
static void Main(string[] args)
{
// Finds the attribute reference and returns "OK"
string name = (new A()).MyProp.MyProp2;
// Uses the stored attribute reference to return "OK"
string name2 = (new A()).MyProp.MyProp2;
}
}

Deserialize my JSOn and bind to list in C# UWP

My Service returns a JSON like below, I want to Parse this and bind category_name to my list, how to do this in C#, UWP apps.
Iam trying to Deserialize this in this way
var content_resp = await response.Content.ReadAsStringAsync();
content_resp = "{ \"root\": " + content_resp.Trim().TrimStart('{').TrimEnd('}') + " }";
var xmlProducts = JsonConvert.DeserializeXNode(content_resp);
var xmlProductNodes = xmlProducts.DescendantNodes();
foreach (XElement xmlProduct in xmlProductNodes)
{
Places pl = new Places();
var node = xmlProducts.Element("category_parent").Value;
pl.category_name = xmlProducts.Element("category_name").Value;
}
}
catch (Exception ex)
{
//throw or return an appropriate response/exception
}
when the debuger comes at this line
var xmlProducts = JsonConvert.DeserializeXNode(content_resp);
it is giving an error like
"This operation would create an incorrectly structured document."
The easiest way that I have found is to use Newtonsoft.Json
Firstly you should create class with data equal to your JSON:
public class AppsData
{
private string _category_id;
private string _category_name;
public string category_id
{
get { return _category_id; }
set { _category_id = value; }
}
public string category_name
{
get { return _category_name; }
set { _category_name = value; }
}
}
Then you can create some helper class:
static class JSONhelper
{
public static IList<T> DeserializeToList<T>(string jsonString)
{
var array = Newtonsoft.Json.Linq.JArray.Parse(jsonString);
IList<T> objectsList = new List<T>();
foreach (var item in array)
{
try
{
objectsList.Add(item.ToObject<T>());
}
catch { }
}
return objectsList;
}
}
Then create instance of List
IList<AppsData> appsdata;
and try to deserialize:
appsdata = JSONhelper.DeserializeToList<AppsData>(stringWithJSON);
If there is no reason to deserialize to XML you can do the following:
Create the class to parse
public class Product
{
public string category_id { get; set; }
[JsonProperty("0")]
public string Zero { get; set; }
public string category_name { get; set; }
[JsonProperty("1")]
public string One { get; set; }
public string category_details { get; set; }
[JsonProperty("2")]
public string Two { get; set; }
public string category_link { get; set; }
[JsonProperty("3")]
public string Three { get; set; }
}
And then
var products = JsonConvert.DeserializeObject<IList<Product>>(your json);

How do I get the type of my ReportItems

This is a continuation of another post. I'm trying to create an interface that will let me walk through a collection of objects, and access the name of the properties of the object.
A Report object will have ReportSections. A ReportSection will have an ICollection of items which will change depending on usage.
Here's how I'm trying to define it now.
public interface IReport
{
string ReportName { get; set; }
ICollection<IReportSection> ReportSections { get; }
}
public interface IReportSection
{
string ReportSectionName { get; set; }
ICollection ReportItems { get; }
}
public abstract class ReportBase : IReport
{
virtual public string ReportType { get; set; }
virtual public string ReportName { get; set; }
virtual public ICollection<IReportSection> ReportSections { get; set; }
}
public abstract class ReportSectionBase : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection ReportItems { get; set; }
}
In my code, I would do this:
public class BookAffiliates : ReportSectionBase
{
public override string ReportSectionName { get { return "Book Affiliates"; } }
public override ICollection ReportItems { get; set; }
}
public class SomeClass
{
public ICollection<AuthorsViewModel> Authors { get; set; }
public ICollection<ProjectSubmissionViewModel> Submissions { get; set; }
public string ProcessAuthorsReport()
{
var report = new ContribAuthorsReport{ ReportType = "CSV" };
var authorAffil = new BookAffiliates {ReportItems = Authors };
report.ReportSections.Add(chapAffil);
var submissionAffil = new BookAffiliates {ReportItems = Submissions};
report.ReportSections.Add(submissionAffil );
return RenderReport(report)
}
}
In RenderReport I would like to walk through the collections and use the PropertyNames:
private string RenderReport(ReportBase currentReport)
{
var reportBody = new StringBuilder();
reportBody.Append(currentReport.ReportName + Environment.NewLine + Environment.NewLine);
foreach (var thisSection in currentReport.ReportSections)
{
reportBody.Append(thisSection.ReportSectionName + Environment.NewLine);
/// ---- Here! Here! I don't know what type, I want the
/// code to get the type based on ReportSectionBase<T>
var firstItem = thisSection.ReportItems.OfType<???Type???>().FirstOrDefault();
// I would actually like to go through each property of
// the ReportItem type and list it here.
foreach(var prop in firstItem.GetType().GetProperties())
{
reportBody.AppendLine(string.Format("{0}:{1}" prop.Name, prop.Value));
}
}
return reportBody.ToString();
}
I'm not sure how to best define this. I'm pretty sure I've done it before, but it's not coming to me.
You would use Reflection to do it.
foreach(var prop in thisItem.GetType().GetProperties())
{
reportBody.AppendLine(string.Format("{0}:{1}" prop.Name, prop.Value));
}
Took a while, a lot of questions, and figuring out what I really wanted to ask. I came up with this.
Here are my interfaces and base classes:
public class ReportBase
{
public ReportBase()
{
ReportSections = new List<IReportSection>();
}
public string ReportType { get; set; }
public string ReportName { get; set; }
public ICollection<IReportSection> ReportSections { get; set; }
}
public interface IReportSection
{
string ReportSectionName { get; }
ICollection ReportItems { get; set; }
}
public class ReportSection<T> : IReportSection
{
public string ReportSectionName { get; set; }
public ICollection<T> ReportItems { get; set; }
ICollection IReportSection.ReportItems
{
get { return ReportItems as ICollection; }
set { ReportItems = value as ICollection<T>; }
}
}
I create my objects like this:
public ReportBase GetContribAuthorsReport
(
ICollection<ProjectAffiliateViewModel> projectAffiliates,
ICollection<SubmissionAffiliateViewModel> submissionAffiliates
)
{
//var caReport = new ContributingAffiliates("CSV", projectAffiliates, submissionAffiliates);
var caReport = new ReportBase { ReportType = "CSV", ReportName = "Reviewers' Contact Information" };
caReport.ReportSections.Add(new ReportSection<ProjectAffiliateViewModel> { ReportItems = projectAffiliates });
caReport.ReportSections.Add(new ReportSection<SubmissionAffiliateViewModel> { ReportItems = submissionAffiliates });
return caReport;//.Report;
}
Then I iterate through the objects like this:
public class DownloadCsvActionResult : ActionResult
{
public ReportBase Report { get; set; }
public string fileName { get; set; }
private string ReportData { get; set; }
public DownloadCsvActionResult(ReportBase report, string pFileName)
{
Report = report;
fileName = pFileName;
ReportData = RenderReport();
}
private string RenderReport()
{
var reportBody = new StringBuilder();
reportBody.AppendLine(Report.ReportName);
reportBody.Append(Environment.NewLine + Environment.NewLine);
foreach (var thisSection in Report.ReportSections)
{
reportBody.Append(thisSection.ReportSectionName + Environment.NewLine);
if (thisSection.ReportItems != null)
{
var itemType = thisSection.ReportItems.GetType().GetGenericArguments().Single();
var first = true;
foreach (var prop in itemType.GetProperties())
{
if (!first) reportBody.Append(",");
DisplayAttribute attribute = prop.GetCustomAttributes(typeof(DisplayAttribute), false)
.Cast<DisplayAttribute>()
.SingleOrDefault();
string displayName = (attribute != null) ? attribute.Name : prop.Name;
reportBody.Append(displayName);
first = false;
}
reportBody.Append(Environment.NewLine);
foreach (var thisItem in thisSection.ReportItems)
{
var firstData = true;
foreach (var prop in itemType.GetProperties())
{
if (!firstData) reportBody.Append(",");
reportBody.Append(prop.GetValue(thisItem,null));
firstData = false;
}
reportBody.Append(Environment.NewLine);
}
}
reportBody.Append(Environment.NewLine);
}
return reportBody.ToString();
}
public override void ExecuteResult(ControllerContext context)
{
//Create a response stream to create and write the Excel file
HttpContext curContext = HttpContext.Current;
curContext.Response.Clear();
curContext.Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
curContext.Response.Charset = "";
curContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
curContext.Response.ContentType = "application/vnd.ms-excel";
//Write the stream back to the response
curContext.Response.Write(ReportData);
curContext.Response.End();
}
}
This gives me what I need for now. Sorry I wasn't as clear in the first place, and thank you for all your help.

Categories