I would like to specify the functionality of an application in a json file that is passed to the application. This will be used to load different libraries.
For example a dictionary containing:
"RunType1" : {
"Init" : "AlgoInit1",
"Body" : "AlgoBody6",
"End" : "AlgoEnd3"
}
This will load the RunType1 dll and chose these functions.
This could use a set of if / else statements
ie
if (initText == "AlgoInit1")
callAlgoInit1();
else (initText == "AlgoInit2")
callAlgoInit2();
etc
But this would fail if i wanted to add new algos to the library, without recoding this.
Is these a more elegant way of choosing or passing the functions to a generic run structure?
I would like to do something like:
runInitAlgo("AlgoInit1"); // take the actual parameter from the config
runBodyAlgo("AlgoBody6");
runEndAlgo("AlgoEnd3");
What is the best solution/patterns for achieving this in C#? So I dont have to hard-code the algo function names into the body of the application.
Thanks.
You can make a Dictionary:
Dictionary<string, Action>actions = new Dictionary<string, Action>();
void Init(){
actions.Add("Init" ,AlgoInit1);
actions.Add("Body" ,AlgoBody6);
actions.Add("End" ,AlgoEnd3);
}
void Do(string action){
actions[action]();
}
private static void AlgoInit1(){
throw new NotImplementedException();
}
You dictionary can be a static or a member field in your class.
If the name corresponds to a DLL, you can use that kind of logic to load dynamically your DLL and then the corresponding class (which inherits from a known interface known for example "Algo") :
Assembly assembly = Assembly.LoadFrom("RunType1.dll");
Type dllType = assembly.GetType("RunType1.Algo");
Algo obj = Activator.CreateInstance(dllType) as Algo;
obj.Init();
obj.Body();
obj.End();
References :
http://msdn.microsoft.com/fr-fr/library/f7ykdhsy.aspx
[fr]http://populnet.blogspot.fr/2008/12/charger-une-dll-dynamiquement.html
You should work around the Strategy Pattern ( http://en.wikipedia.org/wiki/Strategy_pattern ) which is more or less what you want to do.
For a basic C# implementation of the Strategy Pattern you can refer to this document:
http://www.codeproject.com/Articles/346873/Understanding-and-Implementing-the-Strategy-Patter
Related
I'm creating a Java Binding Library for Xamarin.Forms in order to wrap a .jar library.
I got a couple of errors while compiling.
I already solved an issue given by multiple methods having the same signature using "Metadata.xml" in "Transforms" section.
Still, the compiler keeps on bringing out that an appropriate override for this method can't be found:
[Register ("compareTo", "(Ljava/lang/Object;)I", "GetCompareTo_Ljava_lang_Object_Handler")]
public override unsafe int CompareTo (global::Java.Lang.Object o)
{
const string __id = "compareTo.(Ljava/lang/Object;)I";
try {
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
__args [0] = new JniArgumentValue ((o == null) ? IntPtr.Zero : ((global::Java.Lang.Object) o).Handle);
var __rm = _members.InstanceMethods.InvokeAbstractInt32Method (__id, this, __args);
return __rm;
} finally {
global::System.GC.KeepAlive (o);
}
}
Additionally, the owning class of the up method has NO METADATA REFERENCE, as well as the method itself doesn't have one. This makes it difficult even to try removing the node in "Metadata.xml".
To give you a clue, the method "CompareTo" can be found in the following class:
Java.Nio.Charset.Charset
that basically is the class the generator inherits in order to create a
public abstract partial class CustomCharset
Before I try to ignore the entire class, with unexpected consequences on the app I'm about to develop, I would like to know if anyone has ever gone through something similar please. How to solve?
I want have a "pointer" to an object but the object can be one of two classes.
QuickFix.Message newOrderSingle;
if (ecn.versionFIX.Equals(VersionFIX.FSS_FIX44))
{
newOrderSingle = new QuickFix.FIX44.NewOrderSingle(
new ClOrdID(masterForm.OrderBook.GetNewClOrdIDBroker(ecn.brokerCode)),
new Symbol(symbol),
new Side(side),
new TransactTime(DateTime.Now),
ordType = new OrdType(OrdType.LIMIT));
}
else
{
newOrderSingle = new QuickFix.FIX42.NewOrderSingle(
new ClOrdID(masterForm.OrderBook.GetNewClOrdIDBroker(ecn.brokerCode)),
new HandlInst('1'),
new Symbol(symbol),
new Side(side),
new TransactTime(DateTime.Now),
ordType = new OrdType(OrdType.LIMIT));
}
Then later I want to do this, where "set" is a method of QuickFix.FIX44.NewOrderSingle:
newOrderSingle.Set(new Price(limitPrice));
Instead I have to do:
((QuickFix.FIX44.NewOrderSingle) newOrderSingle).Set(new Price(limitPrice));
Which is hard to read.
Can I change "cast" of NewOrderSingle dynamically in some way?
You have some options:
dynamic
You can use dynamic keyword to make "duck typing":
dynamic order= newOrderSingle;
order.Set(new Price(limitPrice));
Unfortunately, you loose intellisense and will get RuntimeBinderException when order has not such a method (is of type FIX42 f.e.).
GenericInvoker
You can use my library:
newOrderSingle.DetermineType()
.When((QuickFix.FIX42 msg) => msg.Set(/* ... */))
.Resolve();
Unfortunately, you need to hardcode type.
To sum up
If you need to use such approach, your classes are badly designed. Consider creating base / abstract class or some inteface:
interface IMessageSetable
{
Set(Price p);
}
public class FIX44 : IMessageSetable
{
// impl
}
then:
if (newOrderSingle is IMessageSetable)
((IMessageSetable)newOrderSingle).Set(price);
if you have access to the source code of QuickFix.Message, you can add it. perhaps you can add the set function to a common interface.
the really dirty way is using reflection. the code would look like this:
newOrderSingle.GetType().GetMethod("Set").Invoke(newOrderSingle, new Price(limitPrice)));
(I guess it will not compile directly, the function parameters needs to be adjusted)
you could also try to use the dynamic datatype
As long as you use the common base class QuickFix.Message you cannot use specific members without casting.
If you have a piece of code where you work with a specific subclass you can do:
if(newOrderSingle is QuickFix.FIX44.NewOrderSingle)
{
QuickFix.FIX44.NewOrderSingle ord44 = (QuickFix.FIX44.NewOrderSingle)newOrderSingle;
// from here on you can work with ord44:
ord44.Set(new Price(limitPrice));
// more code which uses ord44
}
I'm trying to add custom coloring for only certain keywords in my Visual Studio editor for C# code. I want to be able to color any type that implements IDisposable as a different color. Ideally I'd like to create a simple list of classes/interfaces that derive from IDisposable in some sort of configuration that I can edit. (Although if you said there was a method/plugin that would automatically find all disposable types and color them independently that would be the Holy Grail).
I've done a ton of research and it looks like an "editor classifier" extension might do the trick. However I created one that merely tries to color the word "Stream" and although it does hit my code that attempts to highlight that word, it does not end up highlighted in the editor.
I have added my VS extension to Github here
This really seems like this should be fairly straightforward but I have gone down many alleys on this one only to find dead-ends. Is there a simpler way to do this, or is my extension broken?
Update
Very strange. I just ran my extension again and although it does not highlight the text in the editor it highlights all instances of "Stream" in the popup text when you hover over a type/variable! Is there any way to get it to apply to the editor?
Depending on wether you are using Jetbrains Resharper or not you may write a plugin for that. That way you are able not only to add visual notification of IDisposable on a variable but also provide quickfixes if, and only if, it is not beeing called, which is what i am assuming you want to catch. Mind you that i can imagine that there's already a R# plugin for that. I know i've considered this too, but i was too lazy to write a plugin for that.
Don't get me wrong btw - If you're not using r# yet you should consider trying it out.
Among others you'd be working with this: API-QuickFix
There are also ways to define custom keywords, as resharper does, given by a custom markup and apply quickfixes to that.
PS: No i don't work at jetbrains. it's just that good :)
UPDATE:
potential VS Extension fix?
check this one out: MSDN Link Highlighting Text
I tried opening your github project but couldn't so i thought i'll just check msdn instead. it seems you are deriving from the wrong class to fulfill your needs?
MSDN keyword "Editors - Extending the Editor - Walkthrough: Highlighting Text"
I know SO wants code on the site, but msdn links going down is rather unlikely and with the given information the content can be found easily enough :)
I'm a bit late to the party, but hey, why not throw my 2 cents in.
As you've explained in your question, your project has two basic parts:
Finding the classes that implement IDisposable
Highlighting them
The first is by far the hardest, though not impossible. A word-list based approach is probably the simplest, though it should be possible with Roslyn to figure out on the fly which classes inherit IDisposible.
You could also always resort to loading the project's compiled .exe/.dll in the background after a build and figuring out what the types are there, but you'd still have to write some magic glue code to figure out what short class names in the code referred to what actual full-name classes in the assembly.
The second part, highlighting, is quite easy once you know how to do it (it helps that I've spent the last several months working full-time on extending VS). Of course, with Visual Studio, nothing is as simple as it looks (despite the efforts of Microsoft to try to make it user-friendly). So, I've built a sample extension that highlights just classes named "Stream" within C# files to get you started.
The relevant code is below, and the full project source is on GitHub). It starts with a classification-tagger provider:
[Export(typeof(ITaggerProvider))]
[ContentType("CSharp")]
[TagType(typeof(ClassificationTag))]
[Name("HighlightDisposableTagger")]
public class HighlightDisposableTaggerProvider : ITaggerProvider
{
[Import]
private IClassificationTypeRegistryService _classificationRegistry = null;
[Import]
private IClassifierAggregatorService _classifierAggregator = null;
private bool _reentrant;
public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
{
if (_reentrant)
return null;
try {
_reentrant = true;
var classifier = _classifierAggregator.GetClassifier(buffer);
return new HighlightDisposableTagger(buffer, _classificationRegistry, classifier) as ITagger<T>;
}
finally {
_reentrant = false;
}
}
}
Then the tagger itself:
public class HighlightDisposableTagger : ITagger<ClassificationTag>
{
private const string DisposableFormatName = "HighlightDisposableFormat";
[Export]
[Name(DisposableFormatName)]
public static ClassificationTypeDefinition DisposableFormatType = null;
[Export(typeof(EditorFormatDefinition))]
[Name(DisposableFormatName)]
[ClassificationType(ClassificationTypeNames = DisposableFormatName)]
[UserVisible(true)]
public class DisposableFormatDefinition : ClassificationFormatDefinition
{
public DisposableFormatDefinition()
{
DisplayName = "Disposable Format";
ForegroundColor = Color.FromRgb(0xFF, 0x00, 0x00);
}
}
public event EventHandler<SnapshotSpanEventArgs> TagsChanged = delegate { };
private ITextBuffer _subjectBuffer;
private ClassificationTag _tag;
private IClassifier _classifier;
private bool _reentrant;
public HighlightDisposableTagger(ITextBuffer subjectBuffer, IClassificationTypeRegistryService typeService, IClassifier classifier)
{
_subjectBuffer = subjectBuffer;
var classificationType = typeService.GetClassificationType(DisposableFormatName);
_tag = new ClassificationTag(classificationType);
_classifier = classifier;
}
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (_reentrant) {
return Enumerable.Empty<ITagSpan<ClassificationTag>>();
}
var tags = new List<ITagSpan<ClassificationTag>>();
try {
_reentrant = true;
foreach (var span in spans) {
if (span.IsEmpty)
continue;
foreach (var token in _classifier.GetClassificationSpans(span)) {
if (token.ClassificationType.IsOfType(/*PredefinedClassificationTypeNames.Identifier*/ "User Types")) {
// TODO: Somehow figure out if this refers to a class which implements IDisposable
if (token.Span.GetText() == "Stream") {
tags.Add(new TagSpan<ClassificationTag>(token.Span, _tag));
}
}
}
}
return tags;
}
finally {
_reentrant = false;
}
}
}
I've only tested this on VS2010, but it should work for VS2013 too (the only thing that might be different is the class classification name, but that's easy to discover with a well-placed breakpoint). I've never written an extension for VS2012, so I can't comment on that, but I know it's quite close to VS2013 in most respects.
So, one possible solution(I believe this one works):
1) Create your own content type which inherits from csharp.
2) Create new TextViewCreationListener which will swap out all "csharp" content types with your own one, thus potentially "disarming" all the other classifiers.
3) Register your classifier to handle your own content type.
Here is some of the code:
[Export(typeof(IVsTextViewCreationListener))]
[ContentType("csharp")]
[TextViewRole(PredefinedTextViewRoles.Editable)]
class TextViewCreationListener : IVsTextViewCreationListener {
internal readonly IVsEditorAdaptersFactoryService _adaptersFactory;
[Import] internal IContentTypeRegistryService ContentTypeRegistryService = null;
[ImportingConstructor]
public TextViewCreationListener(IVsEditorAdaptersFactoryService adaptersFactory) {
_adaptersFactory = adaptersFactory;
}
#region IVsTextViewCreationListener Members
public void VsTextViewCreated(VisualStudio.TextManager.Interop.IVsTextView textViewAdapter) {
var textView = _adaptersFactory.GetWpfTextView(textViewAdapter);
var myContent = ContentTypeRegistryService.GetContentType(MyContentType);
if(myContent == null)
{
ContentTypeRegistryService.AddContentType(MyContentType, new[] {"csharp"});
myContent = ContentTypeRegistryService.GetContentType(MyContentType);
}
// some kind of check if the content type is not already MyContentType.
textView.TextBuffer.ChangeContentType(myContent, null);
}
#endregion
}
And now, just modify your IClassifierProvider to register with your own content type, as such: [ContentType(MyContentType)]
Iin your own IClassifier, you can basically do your own calculation and once you think you can't handle the stuff, you could pass the control to other classifiers.
If you use MEF and import IClassifierAggregatorService, you can get a "MASTER-classifier" which will run all the logic for you. I haven't implemented it yet, but I've suggestes something similiar in the past, and it seemed to work. Alternatively you could maybe use [ImportMany] with List<IClassifier> and filter out the csharp ones?!
The context is as follows
I want to refactor code by moving it around to different projects
Some of this code comprises of serializable DTOs that are used to
send and receive data across multiple endpoints
If I move the code around, serialization breaks (therefore it is not
backward compatible with older versions of my application)
A solution to this problem is the SerializationBinder which allows me to "redirect" in a sense from one type to another.
I therefore want to create a SerializationBinder to meet this need. However it must do so by meeting the following requirements
The inputs to the SerializationBinder should be a list of old type
to new type mappings. The mapping should include the old assembly
name (no version, no public key token) and the old full name of the
type (namespace and name) as well as the new assembly name and new
full name of the type
For the types that are in the inputs, version numbers of assemblies should be ignored
It should handle generics if my types happen to be in generics
(List, Dictionary, etc) without needing to include the generics in the inputs
For anything that is not in the inputs (i.e. types that have not
moved or .NET types like dataset for example) it should default to
using the out of the box algorithm of the binary serializer
Is this possible or am I dreaming? Is there something out there that already does this? I would assume this is a common problem.
So far I see no easy way of doing 3 and no way at all of doing 4.
Here is an attempt
public class SmartDeserializationBinder : SerializationBinder
{
/// <summary>
/// Private class to handle storing type mappings
/// </summary>
private class TypeMapping
{
public string OldAssemblyName { get; set; }
public string OldTypeName { get; set; }
public string NewAssemblyName { get; set; }
public string NewTypeName { get; set; }
}
List<TypeMapping> typeMappings;
public SmartDeserializationBinder()
{
typeMappings = new List<TypeMapping>();
}
public void AddTypeMapping(string oldAssemblyName, string oldTypeName, string newAssemblyName, string newTypeName)
{
typeMappings.Add(new TypeMapping()
{
OldAssemblyName = oldAssemblyName,
OldTypeName = oldTypeName,
NewAssemblyName = newAssemblyName,
NewTypeName = newTypeName
});
}
public override Type BindToType(string assemblyName, string typeName)
{
//Need to handle the fact that assemblyName will come in with version while input type mapping may not
//Need to handle the fact that generics come in as mscorlib assembly as opposed to the assembly where the type is defined.
//Need to handle the fact that some types won't even be defined by mapping. In this case we should revert to normal Binding... how do you do that?
string alternateAssembly = null;
string alternateTypeName = null;
bool needToMap = false;
foreach (TypeMapping mapping in typeMappings)
{
if (typeName.Contains(mapping.OldTypeName))
{
alternateAssembly = mapping.NewAssemblyName;
alternateTypeName = mapping.NewTypeName;
needToMap = true;
break;
}
}
if (needToMap)
{
bool isList = false;
if (typeName.Contains("List`1"))
isList = true;
// other generics need to go here
if (isList)
return Type.GetType(String.Format("System.Collections.Generic.List`1[[{0}, {1}]]", alternateTypeName, alternateAssembly));
else
return Type.GetType(String.Format("{0}, {1}", alternateTypeName, alternateAssembly));
}
else
return null; // this seems to do the trick for binary serialization, but i'm not sure if it is supposed to work
}
}
This could work (instead of your override).
public override Type BindToType(string assemblyName, string typeName)
{
var m = Regex.Match(typeName, #"^(?<gen>[^\[]+)\[\[(?<type>[^\]]*)\](,\[(?<type>[^\]]*)\])*\]$");
if (m.Success)
{ // generic type
var gen = GetFlatTypeMapping(m.Groups["gen"].Value);
var genArgs = m.Groups["type"]
.Captures
.Cast<Capture>()
.Select(c =>
{
var m2 = Regex.Match(c.Value, #"^(?<tname>.*)(?<aname>(,[^,]+){4})$");
return BindToType(m2.Groups["aname"].Value.Substring(1).Trim(), m2.Groups["tname"].Value.Trim());
})
.ToArray();
return gen.MakeGenericType(genArgs);
}
return GetFlatTypeMapping(assemblyName,typeName);
}
Then you just have to implement your way the function GetFlatTypeMapping (not worrying of about generic arguments).
What you will have to do is to return typeof(List<>) and typeof(Dictionary<,>) (or any other generic you would like to use) when asked.
nb: I said typeof(List<>) ! not typeof(List<something>) ... that's important.
disclaimer: because of the regex "(?[^]]*)", this snipped does not support nested generic types like List<List<string>> ... you will have to tweak it a bit to support it !
Although it might not answer your question this might solve your problem:
I was able to serialize all but one assembly required for deserialization alongside an object structure. The trick is to use reflection to inspect your object structure for types and the assemblies they are defined in. You can then write the assemblies as binary data into an object on serialization and load them into an AppDomain where you can use them to deserialize the rest of the object structure.
You have to put the AppDomain handling, the root object and some base classes into an assembly that won't change and everything else is defined in assemblies depending on this "anchor".
Upsides:
serialization does not break as long as the anchor assembly does not change
can be used for obfuscation, e.g. some required assembly can be hidden in any file
can be used for online updates, e.g. ship the assembly with any data
as far as I'm concerned no problem with generics
Downsides:
security issues as bootstrapping could be used to inject code (some extra work for assembly SecurityEvidences)
AppDomain borders are some work to cross
blows up your serialized data (ok, for files - bad, for communication)
But hey, communication does not break unless you have different client versions and then you can do the bootstrapping on handshake.
Sorry, I can't provide the code as it's too complex and too specific. But I share some insights in these other answers of mine:
difference between DataContract attribute and Serializable attribute in .net
Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true
Is it a hard requirement that you MUST be using the BinaryFormatter for your de/serialization?
If it's not a hard requirement for you to be using the BinaryFormatter to do your serialization, consider alternative serialization methods, such as JSON.Net or ProtoBuf.Net.
Either one of these will create platform- and version-independent serializations of your data.
Alternatively, you can perform binary serialization yourself (which is both faster and smaller than the BinaryFormatter, but generally more code-intensive as you have to be sure to write the serializer and deserializer essentially identically to each other.
If you must use BinaryFormatter, be sure to construct it with FormatterAssemblyStyle.Simple, to get around versioning problems. That tells it to not do the pedantic check of the assembly version.
I'm reading data in from a file and creating objects based on this data. The data format is not under my control and is occasionally corrupt. What is the most appropriate way of handling these errors when constructing the objects in C#?
In other programming languages I have returned a null, but that does not appear to be an option with C#.
I've managed to figure out the following options, but I would appreciate advice from more experienced C# programmers:
Option 1. Read the file inside the constructor and throw an exception when the source data is corrupt:
try
{
obj = Constructor(sourceFile);
... process object ...
}
catch (IOException ex)
{
...
}
Option 2. Create the object, then use a method to read data from the source file:
obj = Constructor();
obj.ReadData(sourceFile);
if (obj.IsValid)
{
... process object ...
}
or possibly throw exceptions on error:
obj = Constructor();
try
{
obj.Read(sourceFile);
... process object ...
}
catch
{
...
}
Option 3. Create the object using a static TryParse method:
if (ObjClass.TryParse(sourceFile, out obj))
{
... process object ...
}
and if so, should I implement option 3 internally using option 1?
public static bool TryParse(FileStream sourceFile, out ObjClass obj)
{
try
{
obj = Constructor(sourceFile);
return true;
}
catch (IOException ex)
return false;
}
I would do something along the lines of option 3):
class ObjectClass
{
protected ObjectClass(...constructor parameters your object depends on...)
{
}
public static ObjectClass CreateFromFile(FileStream sourceFile)
{
.. parse source file
if (parseOk)
{
return new ObjectClass(my, constructor, parameters);
}
return null;
}
}
And then use it like this:
ObjClass.CreateFromFile(sourcefile);
In general the constructor should take as parameters all properties which essentially define the class. Doing heavyweight calculations (like parsing a file) is best left to factory methods as it is usually not expected for the constructor to perform complex and potentially long running tasks.
Update: As mentioned in comments a better pattern is this:
public static ObjectClass CreateFromFile(FileStream sourceFile)
{
.. parse source file
if (!parseOk)
{
throw new ParseException(parseErrorDescription);
}
return new ObjectClass(my, constructor, parameters);
}
public static bool TryCreateFromFile(FileStream sourceFile, out ObjectClass obj)
{
obj = null;
.. parse source file
if (!parseOk)
{
return false;
}
obj = new ObjectClass(my, constructor, parameters);
return true;
}
I would not put anything into a constructor that might throw an exception - except for if something goes really wrong.
If your constructor has a possible return value other than a valid object, you should encapsulate it.
The safest way would probably be to create a factory method (public static function in the class that accepts a file reference and returns a new instance of the class or null). This method should first validate the file and its data and only then create a new object.
If the file data has a simple structure, you can first load it into some local variable and construct the object with this data.
Otherwise, you can still decide - inside of your factory method - if you rather want to try / catch the construction or use any of the other points mentioned above.
Both Options #1 and #3 are good choices and common in the .Net framework. It's also common to provide both for the same type. Consider Int32.TryParse and Int32.Parse. Providing both gives developers a bit more flexibility without detracting from the integrity of the type.
I would strongly advise you to avoid #2. This pattern forces both the type author and type consumer to handle instances of the type in multiple states
Constructed but not fully initialized
Initialized and valid
Initialized and invalid
This puts a burden on every consumer to deal with instances being in all different states (even if the response is to just throw). Additionally it forces a non-standard pattern on consumers. Developers have to understand your type is special and that it needs to be constructed and then initialized. It goes against the standard way objects are created in .Net.
Note for #3 though I would approach it a bit different. The exception form should be implemented in terms of the try form. This is the standard pattern when providing both options to the user. Consider the following pattern
class MyType {
struct ParsedData {
// Data from the file
}
public MyType(string filePath) : this(Parse(filePath)) {
// The Parse method will throw here if the data is invalid
}
private MyType(ParsedData data) {
// Operate on the valid data. This doesn't throw since the errors
// have been rooted out already in TryParseFile
}
public static bool TryParse(string filePath, out MyType obj) {
ParsedData data;
if (!TryParseFile(filePath, out data)) {
obj = null;
return false;
}
obj = new MyType(data);
return true;
}
private static ParsedData Parse(string filePath) {
ParsedData data;
if (!TryParseFile(filePath, out data)) {
throw new Exception(...);
}
return data;
}
private static bool TryParseFile(string filePath, out ParsedData data) {
// Parse the file and implement error detection logic here
}
}
From Microsoft Constructor Design Guidelines (MSDN),
Do throw exceptions from instance constructors if appropriate.
Constructors should throw and handle exceptions like any method. Specifically, a constructor should not catch and hide any exceptions that it cannot handle.
Factory Method is not the right way to approach this problem. See Constructors vs Factory Methods
From Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries
5.3 Constructor Design
Consider using a static factory method instead of a constructor if the
semantics of the desired operation do not map directly to the construction
of a new instance, or if following the constructor design guidelines
feels unnatural.
Do throw exceptions from instance constructors if appropriate.
.NET BCL implementations do throw exceptions from constructors
For example, the List Constructor (Int32), throws an ArgumentOutOfRangeException when the capacity argument of the list is negative.
var myList = new List<int>(-1); // throws ArgumentOutOfRangeException
Similarly, your constructor should throw an appropriate type of exception when it reads the file. For example, it could throw FileNotFoundException if the file does not exist at the specified location, etc.
More Information
Code Contracts
Throwing exceptions from constructor in .Net
Throwing ArgumentNullException in constructor?
Constructor parameter validation in C# - Best practices
All these solutions work, but as you said, C# doesn't allow to return null from a constructor. You either get an object or an exception. Since this is the C# way to go, I wouldn't choose option 3, because that merely mimics that other language you're talking about.
Lots of people [edit] among which is Martin, as I read in his answer :) [/edit] think it is good to keep your constructor clean and small. I'm not so sure about that. If your object is of no use without that data, you could read in the data in the constructor too. If you want to construct the object, set some options, and then read the data (especially with the possility to try again if the read fails), a separate method would be fine as well. So option 2 is a good possibility too. Even better maybe, depending mainly on taste.
So as long as you don't choose 3, choose the one you're the most comfortable with. :)