GetField() return null without reason - c#

my GetField or GetProprety function returns null and I don't understand why
So this is a small code which returns this problem
private void Application_WindowSelectionChange(MSProject.Window Window, MSProject.Selection sel, object selType)
{
MSProject.Task task;
string FieldName = Application.ActiveSelection.FieldNameList[1];
if (sel.Tasks != null)
{
task = sel.Tasks[1];
var typeValue = task.GetType();
var typeProp = typeValue.GetField(FieldName);
var typeGetValue = typeProp.GetValue(task);
}
}
So task is never null as it's a condition for my if.
typeValue gets a value {Name = "__ComObject" FullName = "System.__ComObject"},
but my typeProp and TypeGetvalue are null.

my GetField or GetProprety function returns null
This is because the GetField method takes a long (msdn reference), but you are feeding it a string. Instead of using the FieldNameList property, which returns the name of the field, use FieldIDList which returns the field ID.
Note: use the ActiveCell.Text property to get the value of the first field for the first task in the selection.

Reflection on COM objects do not work as with .NET classes.
As I do not have MS Access installed I can not prove following code.
string FieldName = Application.ActiveSelection.FieldNameList[1];
if (sel.Tasks != null)
{
task = sel.Tasks[1];
long projectField = FieldNameToFieldConstant(FieldName, pjProject);
string value = task.GetField(projectField);
}
Sources:
https://msdn.microsoft.com/en-Us/VBA/Project-VBA/articles/task-getfield-method-project
https://msdn.microsoft.com/en-Us/VBA/Project-VBA/articles/pjfield-enumeration-project
https://msdn.microsoft.com/en-Us/VBA/Project-VBA/articles/application-fieldnametofieldconstant-method-project

Related

'Sequence contains no elements', happening?

It's a WINDOWSFORM
I have combobox, I use this code for auto textboxvalue but I receive this error
Sequence contains no elements
private void cmbOfficeNumber_SelectedIndexChanged(object sender, EventArgs e)
{
using (UnitOfWork db = new UnitOfWork())
if (cmbOfficeNumber.SelectedValue.ToString() != null)
{
txtOfficeName.Text = db.OfficeRepository.GetOfficeNamebyNumber(cmbOfficeNumber.Text);
}
}
And this is my repository code
public string GetOfficeNamebyNumber(string officeNumber)
{
return db.Office.First(g => g.OfficeNumber == officeNumber).OfficeName;
}
EDIT: When using
return db.Office.FirstOrDefault(g => g.OfficeNumber == officeNumber).OfficeName;
I receive a different error
Object reference not set to an instance of an object
If First() results in
Sequence contains no elements
That means the condition in the lambda expression resulted in no hits. Because First requires you to have atleast one match.
If FirstOrDefault().Property results in
Object reference not set to an instance of an object
It means that the lambda expression resulted in no hits, and it returns a default value of the return type. In the case of a reference object it will be null. You then tried to access a property of null which causes the exception.
Simply put. Your problem is that your comparison is returning no hits.
You need to insert a fail safe for this to not crash
Something like:
public string GetOfficeNamebyNumber(string officeNumber)
{
var result = db.Office.FirstOrDefault(g => g.OfficeNumber == officeNumber);
if(result == null)
return string.Empty;
return result.OfficeName;
}
This can also be shortend to
public string GetOfficeNamebyNumber(string officeNumber)
{
var result = db.Office.FirstOrDefault(g => g.OfficeNumber == officeNumber);
return result?.OfficeName ?? string.Empty;
}
Or even
public string GetOfficeNamebyNumber(string officeNumber)
{
return db.Office.FirstOrDefault(g => g.OfficeNumber == officeNumber)?.OfficeName ?? string.Empty;
}
I hope this step by step explanation gives you the information you need to solve the problem.

How to safely check if a dynamic object has a field or not

I'm looping through a property on a dynamic object looking for a field, except I can't figure out how to safely evaluate if it exists or not without throwing an exception.
foreach (dynamic item in routes_list["mychoices"])
{
// these fields may or may not exist
int strProductId = item["selectedProductId"];
string strProductId = item["selectedProductCode"];
}
using reflection is better than try-catch, so this is the function i use :
public static bool doesPropertyExist(dynamic obj, string property)
{
return ((Type)obj.GetType()).GetProperties().Where(p => p.Name.Equals(property)).Any();
}
then..
if (doesPropertyExist(myDynamicObject, "myProperty")){
// ...
}
This is gonna be simple. Set a condition which checks the value is null or empty. If the value is present, then assign the value to the respective datatype.
foreach (dynamic item in routes_list["mychoices"])
{
// these fields may or may not exist
if (item["selectedProductId"] != "")
{
int strProductId = item["selectedProductId"];
}
if (item["selectedProductCode"] != null && item["selectedProductCode"] != "")
{
string strProductId = item["selectedProductCode"];
}
}
You need to surround your dynamic variable with a try catch, nothing else is the better way in makking it safe.
try
{
dynamic testData = ReturnDynamic();
var name = testData.Name;
// do more stuff
}
catch (RuntimeBinderException)
{
// MyProperty doesn't exist
}

TargetParameterCountException when enumerating through properties of string

I'm using the following code to output values of properties:
string output = String.Empty;
string stringy = "stringy";
int inty = 4;
Foo spong = new Foo() {Name = "spong", NumberOfHams = 8};
foreach (PropertyInfo propertyInfo in stringy.GetType().GetProperties())
{
if (propertyInfo.CanRead) output += propertyInfo.GetValue(stringy, null);
}
If I run this code for the int, or for the Foo complex type, it works fine. But if I run it for the string (as shown), I get the following error on the line inside the foreach loop:
System.Reflection.TargetParameterCountException: Parameter count mismatch.
Does anyone know what this means and how to avoid it?
In case anyone asks 'why are you enumerating through the properties of a string', eventually I hope to create a generic class which will output the properties of any type passed to it (which might be a string...).
In this case, one of the string's properties is the indexer for returning the character at the specified location. Thus, when you try to GetValue, the method expects an index but doesn't receive one, causing the exception.
To check which properties require index you can call GetIndexParameters on the PropertyInfo object. It returns an array of ParameterInfo, but you can just check the length of that array (if there are no parameters, it will be zero)
System.String has an indexed property that returns the char in the specified location. An indexed property needs an argument (index in this case) therefore the exception.
Just as reference... if you want to avoid the TargetParameterCountException when reading properties values:
// Ask each childs to notify also, if any could (if possible)
foreach (PropertyInfo prop in options.GetType().GetProperties())
{
if (prop.CanRead) // Does the property has a "Get" accessor
{
if (prop.GetIndexParameters().Length == 0) // Ensure that the property does not requires any parameter
{
var notify = prop.GetValue(options) as INotifyPropertyChanged;
if (notify != null)
{
notify.PropertyChanged += options.OptionsBasePropertyChanged;
}
}
else
{
// Will get TargetParameterCountException if query:
// var notify = prop.GetValue(options) as INotifyPropertyChanged;
}
}
}
Hope it helps ;-)

Avoid object null reference exception when accessing sub-elements that may or may not exist

I have:
An XML with some elements.
A sub-element that may or may not be defined inside this XML.
Need to extract the value of the sub-element when it does exist.
How do I get the value without throwing object-reference errors?
For example:
string sampleXML = "<Root><Tag1>tag1value</Tag1></Root>";
//Pass in <Tag2> and the code works:
//string sampleXML = "<Root><Tag1>tag1value</Tag1><Tag2>tag2Value</Tag2></Root>";
XDocument sampleDoc = XDocument.Parse(sampleXML);
//Below code is in another method, the 'sampleDoc' is passed in. I am hoping to change only this code
XElement sampleEl = sampleDoc.Root;
string tag1 = String.IsNullOrEmpty(sampleEl.Element("Tag1").Value) ? "" : sampleEl.Element("Tag1").Value;
//NullReferenceException:
//Object reference not set to an instance of an object.
string tag2 = String.IsNullOrEmpty(sampleEl.Element("Tag2").Value) ? "" : sampleEl.Element("Tag2").Value;
You can use the null-coalescing-operator for a shortcut:
string tag1= (string)sampleEl.Element("Tag1") ?? string.Empty;
This also uses the fact that LINQ to XML allows the cast operation to get the value of the element (in this case cast to string), but returns null if the element does not exist.
You'll need to check for null in order to prevent them. Given the repeated pattern you're using I would just factor this off into an extension method.
public static string GetElementValue(this XElement parent, string elementName) {
if (parent == null) {
return string.Empty;
}
var element = parent.Element(elementName);
if (element == null || element.Value == null) {
return string.Empty;
}
return element.Value;
}
Now your above code can be replaced with the following
string tag1 = sampleEl.GetElementValue("Tag1");
string tag2 = sampleEl.GetElementValue("Tag2");
The C# ternary operator is pretty good for this:
string tag2 = sampleEl.Element("Tag2") == null ? "" : sampleEl.Element("Tag2").Value;
First you should check if the document is null, remember you are accessing the .Value and this will throw a null reference exception so before you apply .value do a test:
if (sampleEl != null)
//now apply .value
Or ternary:
string tag2 = sampleEl.Element("Tag2") != null ? sampleEL.Element("Tag2").Value : String.Empty
Your code then becomes:
string sampleXML = "<Root><Tag1>tag1value</Tag1></Root>";
//Pass in <Tag2> and the code works:
//string sampleXML = "<Root><Tag1>tag1value</Tag1><Tag2>tag2Value</Tag2></Root>";
XDocument sampleDoc = XDocument.Parse(sampleXML);
//Below code is in another method, the 'sampleDoc' is passed in. I am hoping to change only this code
XElement sampleEl = sampleDoc.Root;
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : String.Empty;
//NullReferenceException:
//Object reference not set to an instance of an object.
string tag2 = sampleEl.Element("Tag2") != null ? sampleEL.Element("Tag2").Value : String.Empty
string tag1 = sampleEl.Element("Tag1") != null ? sampleEl.Element("Tag1").Value : string.Empty;
I came up with this extension method. It requires you to specify the property to access as a lambda, and a default value to use if the actual value or anything up the chain is null:
public static TOut ValueOrDefault<TIn, TOut>(this TIn input, Func<TIn, TOut> projection, TOut defaultValue)
where TOut : class
{
try
{
return projection(input) ?? defaultValue;
}
catch (NullReferenceException)
{
return defaultValue;
}
catch (InvalidOperationException)
{
return defaultValue;
}
}
Usage:
var value = topObject.ValueOrDefault(x=>x.ChildObject.AnotherChild.ChildProperty, String.Empty);
value will be the empty string if topObject, ChildObject, AnotherChild, or ChildProperty are null. If all of those are valid references, the return will be whatever ChildProperty actually is (which could still be the empty string). The catch for the NullReferenceException handles references of child members of a null reference. For nullable types, InvalidOperationException is thrown when accessing the Value property of a null nullable type.
C# 6.0 allows us to make the expression shorter and simpler:
string uniqueIdentifier = myNode.Document?.Element("elem1")?.Element("elem2")?.Attribute("attribute1")?.Value;
Just for the fun of it, here's a solution using LINQ to XML which
requires only one statement and
does not need the ternary operator, so you don't need to specify the name of the tag twice:
string tag1 = sampleEl.Elements("Tag1").Select(x => x.Value).FirstOrDefault();
string tag2 = sampleEl.Elements("Tag2").Select(x => x.Value).FirstOrDefault();
Add ?? "" if you want the empty string instead of null if the tag does not exist.

Passing in null values to a recursive method

I have a method which I want to call itself if a certain condition is true. Initially the method accepts one parameter whose value changes before said condition is reached.
public static void Build(string str)
{
var tree = XmlBuilder.Load();
foreach (var section tree.Sections)
{
str += section.Name;
foreach (var variable in tree.Sections[section].Variables)
{
//
}
}
if (tree.Sections[section].Sections.Count > 0)
{
// here I want to call Build(null)
}
}
I'm not checking for a null value yet - just wanna know if this is possible first? If I say if (str==null) { } that wouldn't work because str has a value, correct? Is there any way of checking what value was PASSED IN to the method rather?
String is a reference type, so it can be null. Be aware that:
string str = null;
str += "foo";
// Now str == "foo"
If you do something like this you can preserve the original value passed into the method:
public static void Build(string str)
{
string localStr = str;
var tree = XmlBuilder.Load();
foreach (var section tree.Sections)
{
localStr += section.Name;
foreach (var variable in tree.Sections[section].Variables)
{
//
}
}
if (tree.Sections[section].Sections.Count > 0)
{
// here I want to call Build(null)
}
}
Just save it into another variable, before changing it. .NET has no way to get the passed in value of a parameter after it has been changed.
ou could send a 'null' to that function where str = null or you could check if it is = "" or String.Empty
Yes, you can pass in null as the parameter.
Then yo ucan check in the code if str == null, and put the required logic.

Categories

Resources