|
I think Microsoft's built in object templates (especially the new class template) should default to public partial , because that's what is used most.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
That question is not as easy as it looks like.
Normally, a class should care about one (and exactly only one) thing.
But still, there may be some aspects differing from the actual purpose of the class.
I use partial classes typically for the purposes of configuration (checking that the configuration is consistent, and that all mandatory dependencies were injected) and another partial class for test accessors (i.e. special functions for setting up that class with a specific state for test purposes, accessing non-public members as reporters for test purposes etc.).
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
I generally like to keep classes tightly factored like that as well, but sometimes, particularly with non-trivial engine style things, you're going to probably have something that's got a lot of tightly coupled functionality that is nevertheless loosely related and your choices are to break encapsulation, greatly expand the surface area of your interconnected class APIs or encase the functionality all in one class. The latter leads to a much smaller test matrix in cases where it's appropriate.
There's a time and a place for breaking just about every rule of thumb. =)
But that being said, I take your point. In most circumstances we wouldn't disagree, and I'm not sure we would in these cases either.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
codewitch honey crisis wrote: greatly expand the surface area of your interconnected class APIs That's another aspect: the Facade Pattern. Seems appropriate to distribute the "facade" class into some partial classes.
True, I use partial classes also with the Decorator Pattern, distinguishing between the "decorated" methods and those which are called without any changes.
There are some practical uses for partial classes.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
Yeah I could see doing that. I don't do a lot of injection and decoration these days because I'm out of the field and mainly researching parsing and compiling which doesn't really require a lot of that.
Still it makes a lot of sense to me to factor orthogonal functionality that way. It's an interesting approach.
Primarily I use them for augmenting classes created with code generation, which as I understand it is what they were primarily designed for, but I really like them in general as another tool in my factoring toolbelt.
I use one on my ParseContext class as well to make a "tear-off" with a bunch of helper functions that aren't necessary for the core functionality but are provided as a convenience.
Partial classes are neat. =)
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
How to write a method in C# that returns String as data type, no matter what datatype we have on excel spread sheet ?
modified 19-Jul-19 16:22pm.
|
|
|
|
|
I seem to have missed the question in your post. Would you care to clarify that?
|
|
|
|
|
Currently, readCell method in ExcelReader only reads String data. I have to Make it more dynamic so it can accept different datatypes like int, double, String, etc..
|
|
|
|
|
You already said that. Repeating it doesn't help.
I'm going to make some assumptions here. A method can only have one return type, so you're either going to have to make a method for each type you want to support, or write a "generic" version that accepts a type parameter and returns the data as the type specified, IF it can be cast to that type.
The problem with this is that your code has to know, or assume, the correct type for the field you're reading ahead of time.
|
|
|
|
|
Actually, the OP did not repeat the first post which had zero content: it's now clear he wants more than just Type 'String.
I upvote your first response for its salutary emetic effect on the OP
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
I don't know when he did it, but the original question has been modified and bunch of it removed.
|
|
|
|
|
I don't discount your psychic powers
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
It is very rude to post your home work and not even have the decency to ask a question. We'll gladly help but you have to actually ask something. We don't mind read (most of us at least) and we won't do everything for you.
The fact that you did not even post an appropriate title makes me think you don't know what to ask because you don't know what you are doing.
Social Media - A platform that makes it easier for the crazies to find each other.
Everyone is born right handed. Only the strongest overcome it.
Fight for left-handed rights and hand equality.
|
|
|
|
|
If you are using OLEDB to read the data you can check the ValueType property on a cell.
|
|
|
|
|
Read a chunk (Excel Range) into a C# DataTable, and look at the Column Types: then you know the Type of any Cell in that Column.
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
I do not understand why there is an UnobservedTaskException in that code at all...
A method in a WCF service is defined as
[OperationContract]
[FaultContract(typeof(RemoteException))]
Task SetInfraredFocus(string _clientName, double _focus);
A WPF application calls out to it via:
public void SetFocus(double _focus)
{
try
{
m_RemoteManualPsControl.SetInfraredFocus(UtilsEnvironment.TerminalName, _focus).Wait();
}
catch (Exception ex)
{
Logger.LogException(Name, ex);
}
}
Note the .Wait() and the catch . That in turn calls the WCF client class
public Task SetInfraredFocus(string _clientName, double _focus)
{
Task task = new Task(() => RemoteChannelProvider.Call(_channel => _channel.SetInfraredFocus(_clientName, _focus)));
task.Start();
return task;
}
True, I ought to add a CallAsync function to our WCF client base class, but that's quite convoluted code there...
The server (a singleton service, multi-threaded) has a simple implementation for the sake of demonstration:
public async Task SetInfraredFocus(string _clientName, double _focus)
{
try
{
await Task.Delay(1);
throw new Exception("Oh f***!");
}
catch (Exception ex)
{
Logger.LogException(Name, ex);
RemoteException.ThrowFaultExceptionFromException(ex);
}
}
And then I get that UnobservedTaskException... Its detail clearly shows where it comes from: it is the RemoteException created from the "Oh f***!" exception of the server. But why does the "catch" in the function on the top not catch the exception?
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
Bernhard Hiller wrote:
Task task = new Task(() => RemoteChannelProvider.Call(_channel => _channel.SetInfraredFocus(_clientName, _focus))); That line looks suspicious to me.
The RemoteChannelProvider doesn't seem to be a built-in class. What's the signature of the Call method?
What I suspect is happening is this:
SetInfraredFocus returns a Task ;Call may or may not discard that task;- Even if it doesn't discard the task, the
new Task constructor definitely discards it - none of the overloads accept a Func<Task> ; - The task returned from the client therefore doesn't observe the result of the task returned from the server. It could even complete before the server call has finished.
If the RemoteChannelProvider.Call method returns the Task , then you should be able to fix this by replacing the client code with:
public Task SetInfraredFocus(string _clientName, double _focus)
{
return Task.Run(() => RemoteChannelProvider.Call(_channel => _channel.SetInfraredFocus(_clientName, _focus)));
} Task.Run has overloads which accept a Func<Task> . The task returned from these will not complete until the inner task has completed, and it will propagate any exceptions correctly.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
That overload does not do the trick either...
The "RemoteChannelProvider" is not a built-in class. The signature is:
public delegate void CallProxyDelegate<in T>(T _channel);
...
void Call(CallProxyDelegate<T> _codeBlock, [CallerMemberName] string _functionName = ""); Some implementation details:
m_ConfigurationChannelFactory = new ConfigurationDuplexChannelFactory<T>(m_CallbackObject, ConfigurationName, null, config);
...
m_CommunicationChannel = (ICommunicationObject)m_ConfigurationChannelFactory.CreateChannel();
...
_codeBlock((T)m_CommunicationChannel); I do not know how that handles a Task.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
OK, then it's definitely throwing the Task away.
How does the RemoteChannelProvider class cope with server methods which return a value?
If it doesn't, you might still be able to hack around it:
public Task SetInfraredFocus(string _clientName, double _focus)
{
return Task.Run(delegate
{
Task result = null;
RemoteChannelProvider.Call(_channel => result = _channel.SetInfraredFocus(_clientName, _focus));
return result;
});
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Perfect! That hack really works.
(But I still will need some time to find out how it works...)
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
A long time ago, Eric wrote: Quote: Any time you find yourself switching on a type in a generic you are almost certainly doing something wrong. Generics should be generic; they should operate identically completely independent of the type.
If T can only be int or string then don't write your code this way at all in the first place. Write two methods, one that returns an int and one that returns a string. Of course, Eric is always right !
I thought the new pattern-matching facilities in C# 7,8 might allow me to simplify a 'Switch based on a Generic Type; here's a compilable (VS 2019, FrameWork 4.8) example:
public TKey GetNextKey(TKey key = default(TKey))
{
if (! KeysUsed.Contains(key))
{
CurrentKey = key;
KeysUsed.Add(key);
return key;
}
switch (KeyType)
{
case Type _ when KeyType == typeof(Int32):
int i = (Int32) (object) key + 1;
CurrentKey = (TKey)(object) i;
break;
case Type _ when KeyType == typeof(string):
string s = (string) (object) key;
s += GetAGuid();
CurrentKey = (TKey)(object)s;
break;
default:
throw new ArgumentException("unsupported TKey Type");
}
KeysUsed.Add(CurrentKey);
return CurrentKey;
} Okay, if you think "case Type _ when KeyType == typeof(Int32):" is simplification ... game over.
What really irritates me is the conversions to object necessary here. This issue came up in a QA question here in 2016; see FES_SiteCore's solution: [^]
references: Mads Torgensen on C# 8 patterns: [^], ReSharper recent blog: [^]
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
modified 18-Jul-19 10:32am.
|
|
|
|
|
BillWoodruff wrote:
TKey key = default(TKey) Since you're using a recent compiler version, you can omit the type name from the default keyword here:
public TKey GetNextKey(TKey key = default)
BillWoodruff wrote:
if (! KeysUsed.Contains(key))
{
CurrentKey = key;
KeysUsed.Add(key);
return key;
} If KeysUsed is a HashSet<TKey> , you can simplify that to:
if (KeysUsed.Add(key))
{
CurrentKey = key;
return key;
}
BillWoodruff wrote:
switch (KeyType) As you've shown, this is a horrible way to solve the problem. I'd be inclined to make the "next key generation" strategy external to the class, and pass it in via the constructor:
public class Foo<TKey>
{
private readonly HashSet<TKey> KeysUsed;
private readonly Func<TKey, TKey> GenerateNextKey;
public Foo(Func<TKey, TKey> generateNextKey, IEqualityComparer<TKey> comparer = default)
{
if (generateNextKey is null) throw new ArgumentNullException(nameof(generateNextKey));
GenerateNextKey = generateNextKey;
KeysUsed = new HashSet<TKey>(comparer ?? EqualityComparer<TKey>.Default);
}
public TKey CurrentKey { get; private set; }
public TKey GetNextKey(TKey key = default)
{
while (!KeysUsed.Add(key))
{
key = GenerateNextKey(key);
}
CurrentKey = key;
return key;
}
} You could then provide static key generators and/or factory methods to simplify creating the class:
public static class Foo
{
public static class Int32
{
public static readonly Func<int, int> GenerateNextKey = i => i + 1;
public static Foo<int> Create() => new Foo<int>(GenerateNextKey);
}
public static class String
{
public static readonly Func<string, string> GenerateNextKey = s => s + GetAGuid();
private static string GetAGuid() => Guid.NewGuid().ToString("N");
public static Foo<string> Create(IEqualityComparer<string> comparer = default) => new Foo<string>(GenerateNextKey, comparer);
}
} Usage:
Foo<int> fooInt = Foo.Int.Create();
Foo<string> fooString = Foo.String.Create(StringComparer.OrdinalIgnoreCase);
Foo<Guid> fooGuid = new Foo<Guid>(_ => Guid.NewGuid());
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks for this detailed response ! My conclusion is that making a "next key" generator ... where the constraint is to ensure keys are unique ... is best off-loaded to a user-supplied Func passed in to the Class instance as a parameter. I can still do validation in the generic class.
I find it wonderful you describe the code as 'horrible' ... and I agree ! ... since your posting the example of casting voodoo here, as a comment: [^] in 2016 was a source
As I study your code and comments, I look forward to more insights.
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|
|
I think what C#/.NET would need (and I'm not sure it's even possible) in order to completely obviate the need for type checking in generics is a way to do true specialization at the very least.
Unless I'm missing something (and I don't have an example offhand but I run into it from time to time), you can't entirely replace the ability to declare both MyClass<t> and MyClass<char> with function template specialization, short of using all static classes or something.
I always felt like either I was missing something, or .NET was here.
Generics always struck me as less elegant than C++ source based templates anyway. I like the idea of them being truly typed and binary but the tradeoffs are irritating.
When I was growin' up, I was the smartest kid I knew. Maybe that was just because I didn't know that many kids. All I know is now I feel the opposite.
|
|
|
|
|
I think all-in-all C# Generics are excellent, and I think the case I've described here is an "edge case."
I don't have your experience with C++ templates to compare it to.
Given my intense respect for Eric Lippert, over many years, I heed his voice.
«Where is the Life we have lost in living? Where is the wisdom we have lost in knowledge? Where is the knowledge we have lost in information?» T. S. Elliot
|
|
|
|