I have a Dictionary which is like Dictionary<Document, File[ n ]>
i want to convert that Dictionary to List<KeyValuePair<Document, File>>
which is flat system
currently i'm using foreach to convert that list is it possible with Linq?
var documentFileList = RepositoryFactory.FileRepository.GetFiles(_case);
var retVal = new List<KeyValuePair<Document, File>>();
if (documentFileList != null)
{
foreach (var docFileKeyPair in documentFileList)
{
if (docFileKeyPair.Value != null)
{
foreach (var fileEntity in docFileKeyPair.Value)
{
var document = docFileKeyPair.Key as Document;
if (document != null)
{
retVal.Add(new KeyValuePair<Document, File>(document, fileEntity));
}
}
}
}
}
Thanks in advance
using Linq, you could do this.
var flattenList = documentFileList.SelectMany(x=>x.Value.Where(v=> v != null).Select(s=> new KeyValuePair<Document, File>(x.Key, s)))
.ToList();
Check this example code
Related
I am new to programming in C#
I want to read the csv file and update the fields in elastic search. I already have this function made by someone else and I want to call this function and update fields.
public static bool UpdateDocumentFields(dynamic updatedFields, IHit<ClientDocuments> metaData)
{
var settings = (SystemWideSettings)SystemSettings.Instance;
if (settings == null)
throw new SettingsNotFoundException("System settings have not been initialized.");
if (ElasticSearch.Connect(settings.ElasticAddressString(), null, out ElasticClient elasticClient, out string status))
{
return ElasticSearch.UpdateDocumentFields(updatedFields, metaData, elasticClient);
}
return false;
}
what I have done myself so far is :
private void btnToEs_Click(object sender, EventArgs e)
{
var manager = new StateOne.FileProcessing.DocumentManager.DocumentManager();
var path = "C:/Temp/MissingElasticSearchRecords.csv";
var lines = File.ReadLines(path);
foreach (string line in lines)
{
var item = ClientDocuments.GetClientDocumentFromFilename(line);
if (item != null)
{
var output = new List<ClientDocuments>();
manager.TryGetClientDocuments(item.AccountNumber.ToString(), 100, out output);
if (output!= null && output.Count <= 0)
{
var docs = new List<ClientDocuments>();
//var doc = docs.Add();
// var doc = docs.Add();
//docs.Add(doc);
foreach (var doc in output)
{
if (!item.FileExists)
{
//insert in elastic search
manager.UpdateDocumentFields(output, );
}
else
{
//ignore
}
}
My problem here is manager.updateDocumentFields() is a function. I am calling it but what I need to pass as a parameter? Thanks in advance.
We have Autodesk Inventor and created a C# Addon.
In this we loop through all Objects like this:
foreach (CurrencyAPIv2.IAssetInstance s in objects)
{
var c = s.NativeObject as ComponentOccurrence;
}
How can we get the connected Object of an Object (the one which is snapped to it). And also the Info to which connector it is connected (snapped)
Michael Navara:
Can you be more specific? CurrencyAPIv2.IAssetInstance is not a member of Inventor API
using CurrencyAPIv2 = Autodesk.Factory.PublicAPI.Currency.v2;
We solved it with the XML-files which can also be watched in AttributeHelper:
void LoadConnectors(Document document, List<ConnectionElement> connections, List<ConnectedComponent> components)
{
var am = document.AttributeManager;
var d = new Dictionary<string, string>();
var entities = am.FindObjects("*", "*");
foreach (var e in entities)
{
try
{
dynamic o = e;
foreach (AttributeSet attrS in o.AttributeSets)
{
foreach (Inventor.Attribute a in attrS)
{
d.Add(o.Name, a.Value as string);
}
}
}
catch(Exception)
{ }
}
foreach (var element in d)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(element.Value);
var connectionNodes = xmlDoc.SelectNodes("//ObjectData[#Type='42']");
var componentNodes = xmlDoc.SelectNodes("//ObjectData[#Type='38']");
// Verbindungen
if (connectionNodes.Count > 0)
{
var link1Node = xmlDoc.SelectSingleNode("//ObjectData/Link1") as XmlElement;
var link2Node = xmlDoc.SelectSingleNode("//ObjectData/Link2") as XmlElement;
var connection = new ConnectionElement();
connection.Name = element.Key;
connection.Link1 = link1Node.GetAttribute("VAL");
connection.Link2 = link2Node.GetAttribute("VAL");
connections.Add(connection);
}
// Komponenten
else if (componentNodes.Count > 0)
{
var componentConnectorNodes = xmlDoc.SelectNodes("//ObjectData/Connector");
var componentConnectors = new List<ComponentConnector>();
foreach (XmlNode cc in componentConnectorNodes)
{
var idNode = cc.SelectSingleNode("Id") as XmlElement;
var displayNameNode = cc.SelectSingleNode("DisplayName") as XmlElement;
var connector = new ComponentConnector();
connector.DisplayName = displayNameNode.GetAttribute("VAL");
connector.Id = idNode.GetAttribute("VAL");
componentConnectors.Add(connector);
}
if (components.FirstOrDefault(x => x.Name == element.Key) != null)
{
components.FirstOrDefault(x => x.Name == element.Key).Connectors.AddRange(componentConnectors);
}
else
{
var component = new ConnectedComponent();
component.Name = element.Key;
component.Connectors = new List<ComponentConnector>();
component.Connectors.AddRange(componentConnectors);
components.Add(component);
}
}
}
}
I am using CsvHelper to read CSV files into Dynamic C# object and I would like to iterate the List<dynamic> using foreach and get property names and values.
FileInfo file = new FileInfo("C:\\Temp\\CSVTest.csv");
List<dynamic> dynObj;
using (var reader = new StreamReader(file.FullName))
using (var csv = new CsvReader(reader))
{
dynObj = csv.GetRecords<dynamic>().ToList();
foreach (var d in dynObj)
{
var properties = d.GetType().GetProperties();
foreach (var property in properties)
{
var PropertyName = property.Name;
var PropetyValue = d.GetType().GetProperty(property.Name).GetValue(d, null);
}
}
}
var properties = d.GetType().GetProperties(); always return 0 but I can see at debug that there are properties.
the CSV file contains this data:
Id,Name,Barnd
1,one,abc
2,two,xyz
Normally, dynamic type has a System.Dynamic.ExpandoObject type object while using it. Its same as a KeyValuePairtype in C#.
Following solution will return list of keys and values from dynamic type.
using (var csv = new CsvReader(reader))
{
dynObj = csv.GetRecords<dynamic>().ToList();
foreach (var d in dynObj)
{
var obj = d as System.Dynamic.ExpandoObject;
if (obj != null)
{
var keys = obj.Select(a => a.Key).ToList();
var values = obj.Select(a => a.Value).ToList();
}
}
}
So I have a model repository that utilizes the C# AWS SDK for Dynamo. Right now it's a bit ugly. What I'd like is to cast-out result items to my model. Going into Dynamo it's great. I just do some type reflection on my Poco classes and shove them in like so:
var doc = new Document();
foreach (PropertyInfo prop in model.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var propName = (string)prop.Name;
// dont add if value is null
if (prop.GetValue(model, null) != null)
{
if (prop.PropertyType == typeof(string))
doc[propName] = (string)prop.GetValue(model, null);
if (prop.PropertyType == typeof(List<string>))
doc[propName] = (List<string>)prop.GetValue(model, null);
if (prop.PropertyType == typeof(float))
doc[propName] = (float)prop.GetValue(model, null);
}
}
But here in the repo, I'd like to not have to write this ugly manual cast when retrieving items. Is there a AWS helper to make this less manual? I guess I could write the inverse of the above loop and get the attribute property names then test for null on each N, S, SS type etc.
var request = new ScanRequest
{
TableName = TableName.User,
};
var response = client.Scan(request);
var collection = (from item in response.ScanResult.Items
from att in item
select new User(att.Value.S, att.Value.N, att.Value.S, att.Value.N, att.Value.S, att.Value.S, att.Value.S, att.Value.S, att.Value.S,
att.Value.S, att.Value.S, att.Value.S, att.Value.S, att.Value.SS, att.Value.SS)).ToList();
return collection.AsQueryable();
You can use the built-in FromDocument method to convert the Dictionary<string, AttributeValue> to your class of type T
List<MyClass> result = new List<MyClass>();
var response = await client.QueryAsync(request);
foreach (Dictionary<string, AttributeValue> item in response.Items)
{
var doc = Document.FromAttributeMap(item);
var typedDoc = context.FromDocument<MyClass>(doc);
result.Add(typedDoc);
}
You can use the Object Persistence Model feature of the .NET SDK. This allows you to annotate your .NET objects with attributes that then direct the SDK how that data should be stored in DynamoDB.
I ended up doing it the LOOOOOONG way. It was kind of fun to use type reflection to create my own casting function. Would have been more fun if it weren't at 2 AM.
The Pavel's answer is more official, but this still works like a charm.
public static T ResultItemToClass<T>(Dictionary<string, AttributeValue> resultItem) where T : new()
{
var resultDictionary = new Dictionary<string, object>();
Type type = typeof(T);
T ret = new T();
foreach (KeyValuePair<string, AttributeValue> p in resultItem)
if (p.Value != null)
foreach (PropertyInfo prop in p.Value.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
if (prop.GetValue(p.Value, null) != null)
{
if (prop.Name == "S")
type.GetProperty(p.Key).SetValue(ret, prop.GetValue(p.Value, null), null);
if (prop.Name == "SS")
type.GetProperty(p.Key).SetValue(ret, (List<string>)prop.GetValue(p.Value, null), null);
if (prop.Name == "N")
type.GetProperty(p.Key).SetValue(ret, Convert.ToInt32(prop.GetValue(p.Value, null)), null);
// TODO: add some other types. Too tired tonight
}
return ret;
}
From the aws Document result class, you can use the instance method: .ToJson(), then deserialise into your class.
Generic method convert Dynamo table to c# class as an extension function.
public static List<T> ToMap<T>(this List<Document> item)
{
List<T> model = (List<T>)Activator.CreateInstance(typeof(List<T>));
foreach (Document doc in item)
{
T m = (T)Activator.CreateInstance(typeof(T));
var propTypes = m.GetType();
foreach (var attribute in doc.GetAttributeNames())
{
var property = doc[attribute];
if (property is Primitive)
{
var properties = propTypes.GetProperty(attribute);
if (properties != null)
{
var value = (Primitive)property;
if (value.Type == DynamoDBEntryType.String)
{
properties.SetValue(m, Convert.ToString(value.AsPrimitive().Value));
}
else if (value.Type == DynamoDBEntryType.Numeric)
{
properties.SetValue(m, Convert.ToInt32(value.AsPrimitive().Value));
}
}
}
else if (property is DynamoDBBool)
{
var booleanProperty = propTypes.GetProperty(attribute);
if (booleanProperty != null)
booleanProperty.SetValue(m, property.AsBoolean());
}
}
model.Add(m);
}
return model;
}
I am trying to generate a new set of wcf interfaces based on existing interfaces.
I am using the Reflection.Emit namespace to accomplish this. My problem is how to copy the old custom attributes from one method to the new method. Every example I have seen of SetCustomAttributes() requires knowing the attribute type beforehand. I need to discover the attribute type at runtime. Any thoughts?
The answer you (frjames) posted is close, but doesn't account for property initializers like...
[ServiceBehavior(Name="ServiceName")]
However, the idea of converting CustomAttributeData to a CustomAttributeBuilder for use in Reflection.Emit is right on.
I ended up having to do this for an open source project (Autofac) and came up with this extension method:
public static CustomAttributeBuilder ToAttributeBuilder(this CustomAttributeData data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
var constructorArguments = new List<object>();
foreach (var ctorArg in data.ConstructorArguments)
{
constructorArguments.Add(ctorArg.Value);
}
var propertyArguments = new List<PropertyInfo>();
var propertyArgumentValues = new List<object>();
var fieldArguments = new List<FieldInfo>();
var fieldArgumentValues = new List<object>();
foreach (var namedArg in data.NamedArguments)
{
var fi = namedArg.MemberInfo as FieldInfo;
var pi = namedArg.MemberInfo as PropertyInfo;
if (fi != null)
{
fieldArguments.Add(fi);
fieldArgumentValues.Add(namedArg.TypedValue.Value);
}
else if (pi != null)
{
propertyArguments.Add(pi);
propertyArgumentValues.Add(namedArg.TypedValue.Value);
}
}
return new CustomAttributeBuilder(
data.Constructor,
constructorArguments.ToArray(),
propertyArguments.ToArray(),
propertyArgumentValues.ToArray(),
fieldArguments.ToArray(),
fieldArgumentValues.ToArray());
}
That one accounts for all the ways to initialize the attribute.
Here is the answer I came up with after some more research.
CustomAttributeBuilder ct = AddAttributesToMemberInfo(methodInfo);
if (ct != null)
{
methodBuilder.SetCustomAttribute(ct);
}
CustomAttributeBuilder AddAttributesToMemberInfo(MemberInfo oldMember)
{
CustomAttributeBuilder ct = null;
IList<CustomAttributeData> customMethodAttributes = CustomAttributeData.GetCustomAttributes(oldMember);
foreach (CustomAttributeData att in customMethodAttributes)
{
List<object> namedFieldValues = new List<object>();
List<FieldInfo> fields = new List<FieldInfo>();
List<object> constructorArguments = new List<object>();
foreach (CustomAttributeTypedArgument cata in att.ConstructorArguments)
{
constructorArguments.Add(cata.Value);
}
if (att.NamedArguments.Count > 0)
{
FieldInfo[] possibleFields = att.GetType().GetFields();
foreach (CustomAttributeNamedArgument cana in att.NamedArguments)
{
for (int x = 0; x < possibleFields.Length; x++)
{
if (possibleFields[x].Name.CompareTo(cana.MemberInfo.Name) == 0)
{
fields.Add(possibleFields[x]);
namedFieldValues.Add(cana.TypedValue.Value);
}
}
}
}
if (namedFieldValues.Count > 0)
{
ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray(), fields.ToArray(), namedFieldValues.ToArray());
}
else
{
ct = new CustomAttributeBuilder(att.Constructor, constructorArguments.ToArray());
}
}
return ct;
}
The code from Travis Illig needs amendment as below to work with .Net Core:
foreach (var namedArg in data.NamedArguments)
{
string argName = namedArg.MemberName;
var fi = data.AttributeType.GetField(argName);
var pi = data.AttributeType.GetProperty(argName);
try this:
MethodInfo mi;
//...
object[] custAttribs = mi.GetCustomAttributes(false);
foreach (object attrib in custAttribs)
attrib.GetType();
i assume you have MethodInfo for your methods