When using the FileHelpers library I am getting a NullReferenceException when trying to write a .csv file.
I have narrowed the problem down. Whenever I have a null decimal? it throws this exception. It works fine on reading, just not writing.
I have included a sample that shows the same problem as my app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args) {
rec record = new rec { id = 1, mydecimal = null };
List<rec> records = new List<rec> { record };
FileHelpers.FileHelperEngine<rec> engine = new FileHelpers.FileHelperEngine<rec>();
Console.WriteLine(engine.WriteString(records));
}
}
[FileHelpers.DelimitedRecord(",")]
public class rec
{
public int id;
public decimal? mydecimal;
}
}
You can use a custom converter.
public class NullableDecimalConverter : FileHelpers.ConverterBase
{
public override object StringToField(string from)
{
return from;
}
public override string FieldToString(object fieldValue)
{
if (fieldValue == null)
return String.Empty;
return fieldValue.ToString();
}
}
You need to modify your record class to add a [FieldConverter()] attribute to any decimal? field.
[FileHelpers.DelimitedRecord(",")]
public class rec
{
public int id;
[FileHelpers.FieldConverter(typeof(NullableDecimalConverter))]
public decimal? mydecimal;
}
Hate to answer my own question, but FileHelpers 2.9.9 fixes this problem. It used to be available on the official site (marked as beta), but can't find it now.
It is however available in NuGet under a package called FileHelpers-stable
Related
I have a logger that records the method name (which I get through reflection) and parameters (which are manually passed to the logger). Here's an example of the proper way to do the logging:
public void Foo() {
// This is correct - the method has no parameters, neither does the logging
Logger.Log();
// Method
}
public void Foo1(int a, int b) {
// Log both of the parameters correctly
Logger.Log(a, b);
// Rest of method
}
However, people will periodically call this incorrectly. For example:
public void Foo1(int a, int b) {
// Didn't record any of the parameters
Logger.Log();
// Rest of method
}
or
public void Foo1(int a, int b, int c) {
// Someone changed the number of parameters but didn't update the logging call
Logger.Log(a, b);
}
The signature of the Log method is:
public void Log(params object[] parameters)
I'd like to have some way of requiring that Logger.Log have the same number of parameters as the method calling it does.
I know how to do this at runtime (just use reflection to get the parameter list for the caller and compare it to what parameters I actually received), but that would be a really bad solution to this I think since the vast majority of the checks would be unnecessary. (It would also mean that you wouldn't know until runtime that you had written it incorrectly, and then only if you happened to execute that particular method).
Right now we're not using FxCop unfortunately (or I'd just write some kind of rule) and I suspect that I wouldn't succeed in changing that fact. Short of writing a compiler plugin of some kind, is there a way to force people to use this method correctly?
You should be able to accomplish this using the new Roslyn API's. You'll want to install the SDK here:
https://marketplace.visualstudio.com/items?itemName=VisualStudioProductTeam.NETCompilerPlatformSDK
Once installed you should go to new project and navigate to Extensibility and you'll see the project type Analyzer with Code Fix (NuGet + VSIX) template. I created a sample project that I used to show the compiler errors:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AnalyzerTest
{
public static class Logger
{
public static void Log(params object[] parameters)
{
}
}
}
namespace AnalyzerTest
{
public class Foo
{
public void Foo1(int a, int b)
{
// Didn't record any of the parameters
Logger.Log();
// Rest of method
}
}
}
I created a separate project for the analyzer and here is the code for the analyzer class:
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Semantics;
namespace Analyzer1
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class LoggerAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "Logging";
internal const string Title = "Logging error";
internal const string MessageFormat = "Logging error {0}";
internal const string Description = "You should have the same amount of arguments in the logger as you do in the method.";
internal const string Category = "Syntax";
internal static DiagnosticDescriptor Rule =
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat,
Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor>
SupportedDiagnostics
{ get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
AnalyzeNode, SyntaxKind.InvocationExpression);
}
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var invocationExpr = (InvocationExpressionSyntax)context.Node;
var memberAccessExpr = invocationExpr.Expression as MemberAccessExpressionSyntax;
if (memberAccessExpr != null && memberAccessExpr.Name.ToString() != "Log")
{
return;
}
var memberSymbol =
context.SemanticModel.GetSymbolInfo(memberAccessExpr).Symbol as IMethodSymbol;
if (memberSymbol == null || !memberSymbol.ToString().StartsWith("AnalyzerTest.Logger.Log"))
{
return;
}
MethodDeclarationSyntax parent = GetParentMethod(context.Node);
if(parent == null)
{
return;
}
var argumentList = invocationExpr.ArgumentList;
Int32 parentArgCount = parent.ParameterList.Parameters.Count;
Int32 argCount = argumentList != null ? argumentList.Arguments.Count : 0;
if (parentArgCount != argCount)
{
var diagnostic = Diagnostic.Create(Rule, invocationExpr.GetLocation(), Description);
context.ReportDiagnostic(diagnostic);
}
}
private MethodDeclarationSyntax GetParentMethod(SyntaxNode node)
{
var parent = node.Parent as MethodDeclarationSyntax;
if(parent == null)
{
return GetParentMethod(node.Parent);
}
return parent;
}
}
}
While in the Analyzer with Code Fix project you can hit F5 (as long as your .Vsix project is the startup project) and it will open up another VS instance and you can choose the project you would like to test the analyzer on.
Here is the result:
It also looks like you will have to install this as a NuGet package instead of a VS Extension, for whatever reason VS Extensions don't affect the build and you will only get the warning:
https://stackoverflow.com/a/39657967/1721372
For a more complete example see here:
https://msdn.microsoft.com/en-us/magazine/dn879356.aspx
I'm trying to learn the attributes in C# dotnet core, so I wrote the 2 below classes.
Attribute class:
using System;
namespace attribute
{
// [AttributeUsage(AttributeTargets.Class)]
[AttributeUsage(AttributeTargets.All)]
public class MyCustomAttribute : Attribute
{
public string SomeProperty { get; set; }
}
//[MyCustom(SomeProperty = "foo bar")]
public class Foo
{
[MyCustom(SomeProperty = "user")]
internal static void fn()
{
Console.WriteLine("hi");
}
}
}
Main class:
using System;
using System.Reflection;
namespace attribute
{
public class Program
{
public static int Main(string[] args)
{
var customAttributes = (MyCustomAttribute[])typeof(Foo).GetTypeInfo().GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
var myAttribute = customAttributes[0];
string value = myAttribute.SomeProperty;
// TODO: Do something with the value
Console.WriteLine(value);
if (value == "bar")
Foo.fn();
else
Console.WriteLine("Unauthorized");
}
return 0;
}
}
}
I need the function Foo.fn() to be executed if the SomeProperty element in the MyCustomAttribute is equal to bar.
My code work fine if I applied it into the class level, but not working on the function level
IMPORTANT NOTE
I'm very new to this, so any advice or feedback to improve my code, is welcomed. thanks
your solution is to find the declared method & in that method find the attribute.
var customAttributes = (MyCustomAttribute[])((typeof(Foo).GetTypeInfo())
.DeclaredMethods.Where(x => x.Name == "fn")
.FirstOrDefault())
.GetCustomAttributes(typeof(MyCustomAttribute), true);
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I'm creating a DLL for a application that I make.
But I got a error when I added the DLL as refference to the console Application but do not know what it means this is the error:
An unhandled exception of type 'System.TypeInitializationException' occurred in ConsoleApplication1.exe
And this is my dll class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace Steap
{
public class SteapAPI
{
public static String URL
{
get;
set;
}
public static XmlReader r = XmlReader.Create(URL + "?xml=1&l=english");
public int getSteamID64()
{
int ID = 0;
r.ReadToFollowing("steamID64");
ID = r.ReadContentAsInt();
return ID;
}
public string getSteamID()
{
string ID = String.Empty;
r.ReadToFollowing("steamID");
ID = r.ReadContentAsString();
return ID;
}
public int getVac()
{
int Vac = 0;
r.ReadToFollowing("vacBanned");
Vac = r.ReadContentAsInt();
return Vac;
}
public bool hasVac()
{
if (getVac() == 0)
{
return false;
}
else
{
return true;
}
}
// =================== [ Aliases
public string getName()
{
return getSteamID();
}
}
}
Console application code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Steap;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SteapAPI sapi = new SteapAPI(); // TypeInitializationException was unhandled error here
SteapAPI.URL = "http://steamcommunity.com/id/bluesephire";
Console.ReadKey();
}
}
}
What is wrong or what is missing
You have exception during initialization of static field of your class that leads to failure to load the class and hence the TypeInitializationException exception.
Particular line:
public static XmlReader r = XmlReader.Create(URL + "?xml=1&l=english");
URL is not initialized at the time method called (and even if it would have static value like URL=#"c:\file.txt" there is no guarantee that one field will be initialized first.
Note from that point any access to the SteapAPI class will throw the TypeInitializationException even if it is not touching fields directly involved into original exception.
In this case you shouldn't be using static fields. Static fields will cause huge problems if you ever create two SteapAPI objects, in that when you set one URL, it will overwrite the other one, and you'll never be able to re-initialize the XmlReader.
Here is how the API class should be rewritten to be a full instance class:
namespace Steap
{
public class SteapAPI
{
public String URL
{
get;
set;
}
public XmlReader r;
public SteapAPI(string url)
{
URL = url;
//NOTE: This is wrong! You can't create an XmlReader with a URL
//and expect it to fetch a web resource.
r = XmlReader.Create(URL + "?xml=1&l=english");
}
public int getSteamID64()
{
int ID = 0;
r.ReadToFollowing("steamID64");
ID = r.ReadContentAsInt();
return ID;
}
public string getSteamID()
{
string ID = String.Empty;
r.ReadToFollowing("steamID");
ID = r.ReadContentAsString();
return ID;
}
public int getVac()
{
int Vac = 0;
r.ReadToFollowing("vacBanned");
Vac = r.ReadContentAsInt();
return Vac;
}
public bool hasVac()
{
if (getVac() == 0)
{
return false;
}
else
{
return true;
}
}
// =================== [ Aliases
public string getName()
{
return getSteamID();
}
}
And then to use it in your program:
class Program
{
static void Main(string[] args)
{
SteapAPI sapi = new SteapAPI("http://steamcommunity.com/id/bluesephire");
Console.ReadKey();
}
}
Its a minor change but the benefits are huge, you should learn more about using constructors and the drawbacks of static fields/properties as it applies to multiple instances. Just remember, a static field/property of a non-static class is shared between all "instances" of the class, so setting one will set all "instances" of that class to the new value. This is especially important when doing I/O operations and file/resource reading/writing.
Reference: How can a dynamic be used as a generic?
public void CheckEntity(int entityId, string entityType = null)
{
dynamic AnyObject = Activator.CreateInstance("Assembly","Assembly.Models.DbModels." + entityType).Unwrap();
CheckWithInference(AnyObject, entityId);
}
private static void CheckWithInference<T>(T ignored, int entityId) where T : class
{
Check<T>(entityId);
}
private static void Check<T>(int entityId) where T : class
{
using (var gr = new GenericRepository<T>())
{
}
}
This enters with CheckEntity(16,"Container");. After the first line runs, AnyObject becomes a blank Assembly.Models.DbModels.Container when inspected with the debugger. If var AnyType = AnyObject.GetType(); is used, then AnyType shows as Assembly.Models.DbModels.Container. However, when the call to CheckWithInference(AnyObject, entityId); is made an exception is thrown.
outer: Object reference not set to an instance of an object.
inner: Microsoft.CSharp.RuntimeBinder.SymbolTable.GetOriginalTypeParameterType(Type t) +10
I made a self-contained example here - but it runs without error :(
Note, this is in asp.net mvc 3 c#
HomeController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace InferenceExample.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
return View();
}
public void CheckEntity(int entityId, string entityType = null)
{
dynamic AnyObject = Activator.CreateInstance("InferenceExample", "InferenceExample.Models." + entityType).Unwrap();
CheckWithInference(AnyObject, entityId);
}
private static void CheckWithInference<T>(T ignored, int entityId) where T : class
{
Check<T>(entityId);
}
private static void Check<T>(int entityId) where T : class
{
var repo = new List<T>();
}
}
}
Example.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace InferenceExample.Models
{
public class Example
{
public int ExampleId { get; set; }
public string Name { get; set; }
}
}
Index.cshtml
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.ActionLink("Start", "CheckEntity", new { entityId = 16, entityType = "Example" })
I am at a loss. Why am getting this exception? I was unable to easily reproduce it. I am not sure what else to include for the example as this is all that the actual code has in it.
The really confusing part is that in the application, when this exception occurs, the action fails. However, upon revisiting the page and trying a second time, there is no exception thrown.
As discussed in C# chat room, the solution here is to bypass dynamic entirely and use reflection to invoke the generic method. Dynamic has some nice features but sometimes causes more trouble than it's worth, especially when it's possible to get the Type object at runtime.
var modelType = Type.GetType("InferenceExample.Models." + entityType + ",InferenceExample");
var checkMethod = typeof(HomeController).GetMethod("CheckWithInference", BindingFlags.NonPublic | BindingFlags.Static);
checkMethod.MakeGenericMethod(modelType).Invoke(null, new object[] { entityId });
Glad to help :)
I am trying to make an instance of a class based on a string that will be retrieved from the User Interface, and then I want to access the properties of the instance of the class.
Here is an overview of what I have so far -
namespace MamdaAdapter
{
public interface IExchange
{
string GetTransport();
}
}
namespace MamdaAdapter
{
public class Exchange
{
public class Arca : IExchange
{
private const string _Transport = "tportname";
public string GetTransport()
{
return _Transport;
}
}
public static IExchange DeriveExchange(string ExchangeName)
{
IExchange SelectedExchange = (IExchange)Activator.CreateInstance(Type.GetType(ExchangeName));
return SelectedExchange;
}
}
}
namespace MyUserInterface
{
public class MainForm
{
private void simpleButton1_Click(object sender, EventArgs e)
{
IExchange SelectedExchange = Exchange.DeriveExchange("Exchange.Arca");
Console.WriteLine(SelectedExchange.GetTransport());
}
}
}
UPDATE:
Right now, I'm getting an Exception that says the "Value cannot be null" which to me means that it is unable to create the instance of the class given the string provided -
The problem here is how you specify the name of your class:
First, specify the namespace. Second, since Arca is an inner class you must use '+' instead of '.'
(...) = Exchange.DeriveExchange("MamdaAdapter.Exchange+Arca");
Assuming you UI doesnt expose the full type name, you typically want a dictionary to associate the display name to the type:
Dictionary<string, Type> _associations = new Dictionary<string, Type>();
Then, you simply instantiate the new object:
if(_associations.ContainsKey(someString))
{
Type selectedType = _associations[someString];
return Activator.CreateInstance(selectedType) as IExchange;
}
throw new ApplicationException("No type defined for that string yo");
If the string is not known at compile time, you basically need to check for the existance of the type:
var type = Type.GetType(someString);
if(type != null)
{
// Do Stuff
}
I wrote a small c# console application to simulate your need, tested ok, hope it helps:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MamdaAdapter;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
IExchange SelectedExchange = Exchange.DeriveExchange("MamdaAdapter.Arca");
Console.WriteLine(SelectedExchange.GetTransport());
}
}
}
namespace MamdaAdapter
{
public interface IExchange
{
string GetTransport();
}
}
namespace MamdaAdapter
{
public class Arca : IExchange
{
private const string _Transport = "tportname";
public string GetTransport()
{
return _Transport;
}
}
}
namespace MamdaAdapter
{
public class Exchange
{
public static IExchange DeriveExchange(string ExchangeName)
{
IExchange SelectedExchange = (IExchange)Assembly.GetAssembly(typeof(IExchange)).CreateInstance(ExchangeName, false, BindingFlags.CreateInstance, null, null, null, null);
return SelectedExchange;
}
}
}
If the Type you are looking for is not defined in the same assembly that is executing Type.GetType you must use the AssemblyQualifiedName (something like MyNamespace.MyClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089), even the FullName is not enough. Otherwise you could first get the assembly containing the class and then execute the GetType method of the Assembly class.