Below is my function :
public static StoreMetaData SetUpdateTime(dynamic myObject)
{
var storeMetaData = new StoreMetaData
{
Created = myObject["StoreMetaData"]["Created"], //Facing problem
Updated = DateTime.Now
};
return storeMetaData;
}
I have three objects :
Teacher
Properties :
public string id{get;set;}
public string name{get;set;}
public StoreMetaData storeMetaData{get;set;}
Student
Properties :
public string id{get;set;}
public string name{get;set;}
public StoreMetaData storeMetaData{get;set;}
StoreMetaData
Properties :
public DateTime? Created { get; set; }
public DateTime? Updated { get; set; }
My problem is how I can get "Created = myObject["StoreMetaData"]["CreatedDate"]".
I want to pass my objects in that function like below:
Part of my code :
teacherObj.StoreMetaData.Created = (currentObject.StoreMetaData != null ? currentObject.StoreMetaData.Created : null);
teacherObj.storeMetaData = SetUpdateTime(teacherObj);
OR,
studentObj.StoreMetaData.Created = (currentObject.StoreMetaData != null ? currentObject.StoreMetaData.Created : null);
studentObj.storeMetaData = SetUpdateTime(studentObj);
At line "Created = myObject["StoreMetaData"]["CreatedDate"]" it shows error. What is the correct format ?
Thanks in advance.
Based purely on the code you posted, your issue is that the storeMetaData property is defined with a lower case first letter, but when you try to access it, you specify it as upper-case.
Try Created = myObject["storeMetaData"]["CreatedDate"];
As an aside, I'm not sure if indexers work like that on dynamic objects. I think they do, but just in case I would use dot syntax as you're dealing with properties.
Created = myObject.storeMetaData.CreatedDate;
Hope that you are passing an object of Teacher or Student so that it contains definition for storeMetaData from that you can access Created which is a property defined inside the StoreMetaData class. Indexers won't help you at this stage, you should use like this:
Created = myObject.StoreMetaData.Created;
Problem solved by me. Thanks every one. :)
Below is my solution :
public static StoreMetaData SetUpdateTime(dynamic myObject)
{
StoreMetaData oStoreMetaData = new StoreMetaData();
oStoreMetaData = myObject.StoreMetaData;
var storeMetaData = new StoreMetaData
{
Created = oStoreMetaData.Created,
Updated = DateTime.Now
};
return storeMetaData;
}
Related
I am trying to add some data to the attribute parameters of below code in C# but every time it gives me the NullObjectRefrence exception. If anyone know about it please.
public class RootObject
{
public string description;
public string external_url;
public string image;
public string name;
public Attribute[] attributes;
}
[System.Serializable]
public class Attribute
{
public string trait_type;
public string value;
}
In The updatethePlayerData() function below i am trying to add the values of trait_type and its corresponding value.
public void updatethePlayerData()
{
RootObject rootObject = new RootObject();
rootObject.description = "aaa";
rootObject.image = "bbb";
rootObject.external_url = "ccc";
rootObject.name = "dddd";
rootObject.attributes[0].trait_type = "character_class";
rootObject.attributes[0].value = "name of cahracter";
}
Finally, I found the solution.
In the "RootObject" class changed the Attribute array to a list as follows:
public List <Attribute> attributes;
in the calling function create an object of the "Attribute" class as follows:
Attribute attribute = new Attribute();
Now I can assign values to the list as follows:
attribute.trait_type = "Some Value";
Hope this helps if someone looking around!
I have a ReportParameter list called lstParam with few values.
List<ReportParameter> lstParam = new List<ReportParameter>();
ReportParameter rpm = new ReportParameter();
rpm.Name = "Department";
rpm.Name = "Location";
lstParam.Add(rpm);
Note: ReportParameter is used from reporting services rdlobject model
Now I need to check if the list has a specific string value and the below code doesn't work for 'ReportParameter' list.
var matchingvalues = !lstParam.Where(stringToCheck => stringToCheck.Contains(stringValue));
if (!lstParam.Any(str => str.Contains(stringValue)))
{
}
Both the above statement didn't help and I get the below error.
'ReportParameter' does not contain a definition for 'Contains' and the best extension
method overload 'Queryable.Contains<string>(IQueryable<string>,string)'
requires a receiver of type 'IQueryable<string>'
ReportParameter class:
public class ReportParameter : ReportObject, INamedObject
{
public ReportParameter();
[DefaultValue(false)]
public bool AllowBlank { get; set; }
public DataTypes DataType { get; set; }
public DefaultValue DefaultValue { get; set; }
[DefaultValue(false)]
public bool Hidden { get; set; }
[DefaultValue(false)]
public bool MultiValue { get; set; }
[XmlAttribute(typeof(string))]
public string Name { get; set; }
[DefaultValue(false)]
public bool Nullable { get; set; }
[ReportExpressionDefaultValueAttribute]
public ReportExpression Prompt { get; set; }
[DefaultValue("")]
[XmlChildAttributeAttribute("Prompt", "LocID", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner")]
public string PromptLocID { get; set; }
[DefaultValue(UsedInQueryTypes.Auto)]
public UsedInQueryTypes UsedInQuery { get; set; }
public ValidValues ValidValues { get; set; }
protected override bool RdlSemanticEqualsCore(ReportObject rdlObj, ICollection<ReportObject> visitedList);
}
Really appreciate any suggestions.
If you want to check only if there ia any item that satisifes your condition, can you please try this code
bool matchingvalues = lstDSParameter.SelectMany(stringToCheck => stringToCheck.Name.Contains(stringValue) || stringToCheck.PromptLocID.Contains(stringValue)).ToList().Count > 0
You describe two lists: lstParam and lstDSParameter. I assume that is a typo and they are the same list.
Each element in lstParam is of type ReportParameter. If you use Enumerable.Where, every item in the were clause represents a ReportParameter. A ReportParameter is not a string, and thus you get the compiler error you described.
You say that you need to check if the list has a specific string value.
Well obviously, because the list does not contain strings, there isn't any. Therefore I assume that you need to check if a certain property of the elements in the sequence contains a specific string value. Let's assume you want to check if any of the Names of the ReportParameters in the sequence contains the specific string value.
To do this, you have to transform every element in the sequence to a string that contains the Name value of each element. In Linq, whenever you need to transform elements from a sequence into something else you use Enumerable.Select:
List<ReportParameter> lstParam = ...;
var reportParameterNames = lstParam.Select(reportParameter => reportParameter.Name);
"From every reportParameter in lstParam, take reportParameter.Name, and put these names in a new sequence called reportParameterNames"
Now to check if any of the reportParameterNames equals the SpecificStringValue you can use Enumerable.Any:
bool lstParamContainSpecificStringValue = reportParameterNames
.Any(name => name == SpecificStringValue);
"Check if any element in the reportParameterNames sequence equals SpecificStringValue"
This article helped me to understand LINQ, and learned me how to use it
It seems you are using the ReportParameter from the wrong namespace. Try using the one in the Microsoft.ReportingServices.ReportRendering Namespace. This one contains a Value property.
MSDN ReportParameter Class
So you can use it like this:
if (!lstParam.Any(p => p.Value?.ToString().Contains(stringValue)))
{
}
have look at the question this.
may be reflection can help you here.
I suggest you to 1st loop through the
List<ReportParameter> lstParam = new List<ReportParameter>();
foreach(var item in lstParam )
{
//and then loop through class properties
Type type = item.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties )
{
//now here you can play with class properties
//like property.Name or property.Value
//place your check here
}
}
I haven't tested this code, just suggesting you the path to go. I hope this will help, trying to find some other efficiente way to get rid of loops.
I have tried to write a generic method for the below mentioned code snippet.But it gives error on the OrderBy clause ? Could you tell me why ?
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<StateListDto>>(cache.StringGet(AppConsts.States));
if (values != null) return new ListResultOutput<StateListDto>(values.OrderBy(o => o.Name).ToList());
Generic method :
public ListResultOutput<T> GetCache<T>(string cacheKey)
{
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
return values != null ? new ListResultOutput<T>(values.ToList().OrderBy(o=>o.Name)) : null;
}
call :
var values = GetCache<StateListDto>(AppConsts.States);
StateListDto.cs
public class StateListDto
{
public string Code { get; set; }
public string Name { get; set; }
}
It gives this error: (click to see the full size image)
If you are expecting to use this for more than just StateListDto I would suggest creating an interface or base class that does have the property called Name then you can guarantee it exists.
Something like:
public interface IDto
{
string Name { get; }
}
and then you can change your method to:
public ListResultOutput<T> GetCache<T>(string cacheKey) where T: IDto
{
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
return values != null ? new ListResultOutput<T>(values.ToList().OrderBy(o=>o.Name)) : null;
}
You can send the way you want to order by as a parameter like this:
public ListResultOutput<T> GetCache<T>(string cacheKey, Func<T,object> selector)
{
var cache = RedisConnectorHelper.Connection.GetDatabase();
var values = JsonConvert.DeserializeObject<List<T>>(cache.StringGet(cacheKey));
return values != null ? new ListResultOutput<T>(values.OrderBy(selector).ToList()) : null;
}
call :
GetCache<StateListDto>("yourKey", i=>i.Name);
In this way you don't force your class to implement anything - and you can choose to order by other parameter in your code
But all are having Name property.
Then create a common interface for them, something like this:
public interface INamed
{
string Name { get; }
}
And all your models with that property can implement that interface:
public class StateListDto : INamed
Then you can use that interface as a type constraint on the generic method:
public ListResultOutput<T> GetCache<T>(string cacheKey) where T: INamed
That way the compiler can guarantee that the type of T will have a Name property.
Note that a base class, concrete or abstract, can also be used to accomplish this. Though personally I prefer to use interfaces over inheritance unless there's a specific reason to use inheritance.
I have the following business objects:
public abstract class Product
{
public int Id { get; set; }
public bool OnStock { get; set; }
}
public class ProductForImport : Product
{
public int ImportId { get; set; }
}
public class ProductForExport : Product
{
public int ExportId { get; set; }
public bool IsExportable { get; set; }
public bool IsUsable { get; set; }
public string OtherParam {get; set;}
public static implicit operator ProductForExport(ProductForImport pfi)
{
ProductForExport p = new ProductForExport();
p.Id = pfi.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
so I can convert between the two types:
static void Main(string[] args)
{
ProductForExport pfe = new ProductForExport();
pfe.Id = 1;
pfe.OnStock = true;
ProductForImport pfi = new ProductForImport();
pfi.ImportId = 200;
ProductForExport pfe2 = (ProductForExport)pfi;
}
this works OK.
I have 100.000 ProductsForImport items.
If I understand correctly, if I convert them to ProductsForExport items, I'll have 100.000 +100.000 items in memory - that's reasonable.
My problem is: I have to send these "ProductForExport" objects through JSON services, each service just need some subset of the properties of each type:
servicecall1 should return ProductForExport1{ExportId,IsExportable}
servicecall2 should return ProductForExport2{ExportId,IsUsable}
Question: should I write an implicit conversion similar to the above example for these new types - ProductForExport1 and ProductForExport2 (so basically create 100.000+100.000 new objects)
or
somehow can I just "hide" the unwanted properties with some magic from the original type without the need to create new instances?
thanks,
b.
If you ned such kind of decoupling and separation of entities - you can create DTO object along with each business object and use DTO to communicate with Service.
But if you have a lot of business entities consider an other approach to avoid maintenance hell.
public sealed class ExportProductDto
{
public(ProductForExport exportProduct)
{
// initialize fields
this.ExportId = exportProduct.ExportId;
}
public int ExportId { get; private set; }
}
BTW,
An overkill solution with operator overload, use Adapter pattern to convert between product types
To decouple adapting from entities itself implement following interface your self:
public interface IProductAdapter<TImport, TExport>
{
TImport ToImportProduct(TExport exportProduct);
TExport ToExportProduct(TImport importProduct);
}
Or an other adapter approach:
// Implement this interface for ProductForImport class
// public class ProductForImport : IExportProductAdapter, Product
public interface IExportProductAdapter
{
ProductForExport ToExportProduct();
}
// Implement this interface for ProductForExport class
// public class ProductForExport : IImportProductAdapter, Product
public interface IImportProductAdapter
{
ProductForImport ToImportProduct();
}
EDIT: Answer to comments
// An example of IExportProductAdapter adapter implementation
public sealed class ProductForImport : Product, IExportProductAdapter
{
public int ImportId { get; set; }
public ProductForExport ToExportProduct()
{
ProductForExport p = new ProductForExport();
p.Id = this.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
And then instead of:
ProductForExport pfe2 = (ProductForExport)pfi;
You can do:
ProductForExport pfe2 = pfi.ToExportProduct();
I would create light objects specifically for returning through the service with only the required fields. Then use Automapper or something like that to map them.
I don't recommend using operator overloading if you can avoid it. I have seen many issues where a developer didn't realize when the operator overload was being called and something unexpected happened.
If you are using WCF, you can apply the IgnoreDataMemberAttribute to properties you wish not to serialize.
Have a look at the ScriptIgnoreAttribute to exclude properties from json serialization.
It took me a few reads but I don't think your problem is about implicit conversion as much as how to send data via json right?
If you have your object collections of Import or Export object you can use the JavaScriptSerilizer and some anonymous types to slice and dice what data you send.
You can use Linq to select specific properties of your object in a collection, and define an anonymous type "on-the-fly" to serialize out as a json string like this:
List<ProductForExport> exportList; //the list to export
JavaScriptSerializer jss = new JavaScriptSerializer();
string output = string.Empty;
output = jss.Serialize(new
{
isExportable = True, //static named properties
iTotalProducts = exportList.Count, //dynamic values
productDataArray = exportList //all data in an array object
});
//Or build the result using just a few properties of the collection:
foreach (ExportProduct exProd in exportList)
{
output += jss.Serialize(new
{
exProd.IsExportable,
exProd.ExportID
});
}
I discovered yesterday that I can't have a Class that uses a field named "Type" this is probably reserved.
Although the field may be reserved you still can't set anyObject.Type if it doesn't have a Type field defined as a public string. Ignoring any getters and setters and jumping directly to changing YourObject to "whatever" string.
Try this for yourself. Define a Type field and try setting it.
This should be reported to Microsoft so no one will use "Type" as a field in the future, there is no warnings/errors along trying to define it.
public Point_Extended(Point p, booking b)
{
this.ID = p.ID;
this.Type = p.Type;
this.Status = p.Status;
this.Size = p.Size;
this.Coords = p.Coords;
this.Color = p.Color;
this.BuildingID = p.BuildingID;
this.Login = b.Login;
this.Starts = b.Starts;
this.Hours = b.Hours;
this.BookingID = b.ID;
}
If there is a name abiguity - just use this.Type / obj.Type (instance), TypeName.Type (static) or System.Type (the type). Or in really nasty cases, global::System.Type. This works just fine and matches the question (I think):
static class Program
{
static void Main() {
Test anyObject = new Test();
anyObject.Type = "abc";
}
}
class Test
{
public string Type;
}
You are defining "Type" in a scope local to your class, e.g.
class SomeClass
{
public string Type { get; set; }
}
and then using it in some method of that class, e.g.
class SomeClass
{
public string Type { get; set; }
public void DoSomeStuff()
{
Type = "Foo";
}
}
This is ambiguous between "Type" in SomeClass (a property) and "Type" in namespace System (a type).
Nevermind.
It was the ToString() override representation that confused me to think the Type was changed.