interface parentInterface
{
public String methodA(/*define parameters name and dataType*/);
}
and
public class childA : parentInterface
{
public String methodA(String a, int b, String c, long d){}
}
public class childB : parentInterface
{
public String methodA(int e, String f, String g){}
}
I want to define interface method's parameters name and data type
Make a New Parameter
This can often be solved by using a class or struct to use as single parameter rather than the built-in Types.
The Interface
You know what to expect from a class when it implements a familiar interface. We know that all classes implementing the IEnumerable interface can be used in a foreach loop. By convention, the name of the interface is "I" followed by a description of an ability. It is typical for the name to end with the suffix "-able".
-able
Suffix forming adjectives meaning:
1 -able to be [as in] calculable.
2 -having the quality of [as in] comfortable.
Oxford English Dictionary
Let's rename parentInterface and MethodA() to give a clear example of how this normally works (and to avoid negative sanctions):
public interface ITreatable
{
Treatment GetTreatment();
}
Well, finding the cure may not be so easy, even if the object represents a treatable illness. Here's some examples:
public class TheFlu : ITreatable
{
public Treatment GetTreatment(int year)
{
// return some object, Treatment, based on the flu season.
}
}
public class Hangover : ITreatable
{
public Treatment GetTreatment()
{
return Treatment.Empty; // no parameters necessary.
}
}
public class Insomnia : ITreatable
{
public Treatment GetTreatment(FamilyHistory occurances, LabResult lab)
{
// return Some Treatment object that can be different based on the
// calculated risk from the arguments.
}
}
What We're Really Missing Here
I don't know biology, but the concept is still the same. You have a group of ITreatable illness objects that need to have a GetTreatment() method; however, they use different criteria for making calculations. We need Symptoms.
public class Symptoms
{
public FamilyHistory History;
public DateTime Time;
public LabResult Lab;
public BloodTest BloodTest;
public TimeSpan SymptomTime;
public IsCritical IsCritical;
}
Now, the objects can parse the symptoms in their own method, and our interface will look like this:
public interface ITreatable
{
Treatment GetTreatment(Symptoms symptoms);
}
You have two different methods
public String methodA(String a, int b, String c, long d){}
and
public String methodA(int e, String f, String g){}
that represent two different contracts to childA and childB respectively. You cannot define an interface with a single methodA that fits both definitions. What you seek to do is not possible.
Note that you could define both overloads in your interface, but then each class implementing that interface would have to implement both overloads.
You could use an interface method with a variable number of arguments using the params keyword. But you then need to cast each argument to the appropriate type, which is a bit error prone.
public interface IFoo
{
void DoWork(params object [] arguments);
}
public class Foo : IFoo
{
public void DoWork(params object [] arguments)
{
string a = (string)arguments[0];
int b = (int)arguments[1];
string c = (string)arguments[2];
long d = (long)arguments[3];
Console.WriteLine("a={0}, b={1}, c={2}, d={3}", a,b,c,d);
}
}
public class AnotherFoo : IFoo
{
public void DoWork(params object [] arguments)
{
int e = (int)arguments[0];
string f = (string)arguments[1];
string g = (string)arguments[2];
Console.WriteLine("e={0}, f={1}, g={2}", e,f,g);
}
}
void Main()
{
var foo = new Foo();
foo.DoWork("a",1, "c",2L);
var foo1 = new AnotherFoo();
foo1.DoWork(1,"f", "g");
}
Methods with different parameters cannot both implement the same interface method declaration. If your method signature does not match that of the interface, you are not implementing the interface.
You can achieve this though, but it is not a good design since the interface is not telling you anything about the method:
interface parentInterface
{
string methodA(params object[] asd);
}
public class childA : parentInterface
{
public string methodA(params object[] p)
{
string a = p[0] as string;
int b = (int)p[1];
string c = p[2] as string;
long d = (long)p[3];
return string.Empty;
}
}
public class childB : parentInterface
{
public string methodA(params object[] p)
{
int e = (int)p[0];
string f = p[1] as string;
string g = p[2] as string;
return string.Empty;
}
}
Related
I have a generic method like this (simplified version):
public static TResult PartialInference<T, TResult>(Func<T, TResult> action, object param)
{
return action((T)param);
}
In the above, param is of type object on purpose. This is part of the requirement.
When I fill in the types, I can call it like this:
var test1 = PartialInference<string, bool>(
p => p.EndsWith("!"), "Hello world!"
);
However, I'd like to use type inference. Preferably, I would like to write this:
var test2 = PartialInference<string>(
p => p.EndsWith("!"), "Hello world!"
);
But this does not compile. The best I came up with is this:
var test3 = PartialInference(
(string p) => p.EndsWith("!"), "Hello world!"
);
The reason I would like to have this as a type parameter and still have the correctly typed return type is because my actual calls look something like this:
var list1 = ComponentProvider.Perform(
(ITruckSchedule_StaffRepository p) => p.GetAllForTruckSchedule(this)
)
Which is very ugly and I would love to write as something like this:
var list2 = ComponentProvider.Perform<ITruckSchedule_StaffRepository>(
p => p.GetAllForTruckSchedule(this)
)
You can split t into a generic method on a generic type:
class Foo<TOuter> {
public static void Bar<TInner>(TInner arg) {...}
}
...
int x = 1;
Foo<string>.Bar(x);
Here the int is inferred but the string is explicit.
What you are trying to achieve is not possible. You need to specify both generic arguments or none of the them if inference is possible.
You can use reflection... like this below
Here is an example of how to call a extension method with two generic parameters.
We have to ways to execute the extension method:
a) Directly from an abstract base class
b) From an instance object that derived from that base class
Not mandatory to implement like so, but I found it very handy.
a) You must supply the two generic arguments as usual.
b) You already have one of the generic types since you are using an instance. The other generic parameter must by passed as type argument, you cannot pass it a second generic parameter due to ambiguity.
(see How to pass 2 generics types into an extension method)
public interface IEntityDto
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your generic types don't need interface constraints
}
public interface IRowVersion
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your generic types don't need interface constraints
}
public interface IPropertyMappingValue
{
// Not relevant to this example, how is defined , is just an interface, it could be removed, if your returned object don't need interface constraints
string Value { get; set; }
}
public class PropertyMappingValue : IPropertyMappingValue
{
// Not relevant to this example, how is defined , is just an object, returned by our extension method
public string Value { get; set; }
}
public abstract class EntityBase
{
public static IPropertyMappingValue GetPropertyMappingValue<TEntity, TEntityDto>(string name) where TEntity : class, IRowVersion where TEntityDto : class, IEntityDto => EntityExtensions.GetPropertyMappingValue<TEntity, TEntityDto>(name);
}
// Sample Class
public class Entity : IRowVersion
{
}
// Sample Class
public class EntityDto : EntityBase, IEntityDto
{
}
public static class EntityExtensions
{
public static IPropertyMappingValue GetPropertyMappingValue<TEntityDto>(this TEntityDto instance, Type entityType, string name) where TEntityDto : class, IEntityDto
{
if (!typeof(IRowVersion).IsAssignableFrom(entityType))
throw new ArgumentException($"{entityType} do not implements {typeof(IRowVersion)}");
var method = typeof(EntityExtensions).GetMethod(nameof(GetPropertyMappingValue), new[] { typeof(string) });
var typeArgs = new[] { entityType, typeof(TEntityDto) };
var constructed = method?.MakeGenericMethod(typeArgs);
var result = constructed?.Invoke(null, new object[] { name });
return result as IPropertyMappingValue;
}
public static IPropertyMappingValue GetPropertyMappingValue<TEntity, TEntityDto>(string name) where TEntity : class, IRowVersion where TEntityDto : class, IEntityDto
{
//TO DO YOUR JOB HERE TO GET A VALID RETURNED OBJECT, as this is an example I will return a fake
// THE CODE IS JUST AN EXAMPLE of doing something with the types, but is not relevant for this example
//
var foo = typeof(TEntityDto);
var bar = typeof(TEntity);
//
return new PropertyMappingValue { Value = name }; // returning just a fake object
}
}
public class UnitTest
{
private readonly ITestOutputHelper _console;
public UnitTest(ITestOutputHelper console)
{
_console = console;
}
[Fact]
public void Test()
{
var oneWayOfExecuting = EntityBase.GetPropertyMappingValue<Entity, EntityDto>("Hello world"); //using a abstract base
_console.WriteLine(oneWayOfExecuting.Value);
var entityDto = new EntityDto();
var anotherWayOfExecuting = entityDto.GetPropertyMappingValue(typeof(Entity), "Hello world"); //using the extension method
_console.WriteLine(anotherWayOfExecuting.Value);
Assert.Equal("Hello world", oneWayOfExecuting.Value);
Assert.Equal("Hello world", oneWayOfExecuting.Value);
}
imagine a generic class B
public class B<T> : IB
{
public void Foo(object parameter)
{
var param = (T)parameter;
//...
}
}
And a class A, which get's a collection of Bs passed through it's constructor. Notice im using the interface IB as type there.
public class A
{
public A(IEnumerable<IB> collectionOfBs) {}
}
Sometime later, I want to execute some Method on class A, let's say foo, which will take a collection of objects of type T, where T is the generic type of the instance of B passed in the constructor. so these types have to match.
public void foo(IEnumerable<object> param)
{
for (int i = 0; i < collectionOfBs.Count(); i++)
{
collectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
}
}
Right now im passing an IEnumerable<object> and cast to type T inside of foo, that will work but I'm wondering if I could have this type check at compile time instead?
Any Ideas if thats possible or not?
Thanks
You can try this using a generic method for the type of the provided parameter.
It does not ensure that TParam and T are same, since you have a non generic interface, but is it the best you can do, as I know, according to a first study of your problem...
Because there is no diamond operator in C# to allow true generic polymorphism on open types.
public interface IB
{
void Foo<TParam>(TParam parameter);
}
public class B<T> : IB
{
public void Foo<TParam>(TParam parameter)
{
var param = parameter;
Console.WriteLine("param type: " + param.GetType().Name);
}
}
public class A
{
private IEnumerable<IB> CollectionOfBs;
public A(IEnumerable<IB> collectionOfBs)
{
CollectionOfBs = collectionOfBs;
}
public void Foo(IEnumerable<object> param)
{
if ( param.Count() < CollectionOfBs.Count() )
throw new ArgumentException();
for ( int i = 0; i < CollectionOfBs.Count(); i++ )
CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
}
}
Test method
static void Test()
{
var listInstances = new List<IB> { new B<int>(), new B<double>(), new B<string>() };
var container = new A(listInstances);
var listParams = new List<object> { 2, 4.3, "test" };
container.Foo(listParams);
}
Output
param type: Int32
param type: Double
param type: String
Considerations
The problem here is that any bad matching parameter type can be passed.
For example with the Test(), you can have a double instead of the first integer and it works: you get a Double on your Int32 instance...
param type: Double
param type: Double
param type: String
Having the diamond operator <> you will be able to use a generic interface and parse on a closed constructed types list... and your design will have a better smell:
public interface IB<T>
{
void Foo(T parameter);
}
public class B<T> : IB<T>
{
public void Foo(T parameter)
{
var param = parameter;
Console.WriteLine("param type: " + param.GetType().Name);
}
}
public class A
{
private IEnumerable<IB<>> CollectionOfBs;
public A(IEnumerable<IB<>> collectionOfBs)
{
CollectionOfBs = collectionOfBs;
}
public void Foo(IEnumerable<object> param)
{
if ( param.Count() < CollectionOfBs.Count() )
throw new ArgumentException();
for ( int i = 0; i < CollectionOfBs.Count(); i++ )
{
CollectionOfBs.ElementAt(i).Foo(param.ElementAt(i));
}
}
}
Hence with that, any bad matching type of parameter will raise an exception at runtime.
When you want consistent generic type checking, you need to apply generics consistently. Currently, you are using a half-way approach: B<T> is generic, but IB is not. Then you have a non-generic class A, which couples to the non-generic interface IB, but you want compile-time type checking of T, which both, A and IB know nothing about (only to internally cast it to T). That's a bit of a problem.
From the usage of your classes/interface it seems obvious that you don't expect mixed IB implementations in A, so what you can do is to consistently apply the generic type parameter T on all types:
public class B<T> : IB<T>
{
public void Foo(T parameter)
{
var param = parameter;
//...
}
}
public class A<T>
{
public A(IEnumerable<IB<T>> collectionOfBs) {}
public void foo(IEnumerable<T> param)
{
collectionOfBs.Zip(param, (b, t) => { b.Foo(t); return 0 });
}
}
Note that I replaced your approach with for and ElementAt by Enumerable.Zip.
I have taken the following class from another SO question:
public class Range<T> where T : IComparable<T>
{
public T Minimum { get; set; }
public T Maximum { get; set; }
public override string ToString() { return String.Format("[{0} - {1}]", Minimum, Maximum); }
public Boolean IsValid() { return Minimum.CompareTo(Maximum) <= 0; }
public Boolean ContainsValue(T value)
{
return (Minimum.CompareTo(value) <= 0) && (value.CompareTo(Maximum) <= 0);
}
}
I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
public class Ranges<T> where T : Range<T>
{
private List<Range<T>> rangelist;
public void add(Range<T> range)
{
rangelist.Add(range);
}
public Boolean ContainsValue(T value)
{
foreach (Range<T> range in rangelist)
{
if (range.ContainsValue(value)) return true;
}
return false;
}
}
However, i am getting the error The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Range<T>'. There is no implicit reference conversion from 'T' to 'System.IComparable<T>'.
What exactly is going wrong here?
You don't seem to need the constraint where T : Range<T>
Just repeat the comparable constraint:
public class Ranges<T> where T : IComparable<T>
{
}
If you rewrite your second class slightly, you'll see why:
public class Ranges<U> where U : Range<U>
{
private List<Range<U>> rangelist;
public void add(Range<U> range)
{
rangelist.Add(range);
}
...
}
The error is telling you the compiler does not know if U is convertible to IComparable<U>, which is apparent from the declaration of Ranges<U> and Range<T> (Range<T> does not implement any interfaces).
More importantly, you have a recursing generic argument!
If U is Range<U>, then your class looks like Ranges<Range<T>> where T is U, and so on and so forth.
From what I can tell, you're not looking to write:
Ranges<Range<int>> x = ...;
But rather:
Ranges<int> x = ...;
Which would mean:
public class Ranges<T> where T : IComparable<T>
{
private List<Range<T>> rangelist;
...
You don't need new classes for that, use linq.
list1.All(x=>list2.Any(y=>y == x))
UPDATE: You are saying : I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
So effectively you have list of lists. Or more generally IEnumerable of IEnumerables.
There is enough standard generic data structures to handle this scenario
public static class ListOfListExtention {
public static bool ContainAny( this List<List<int>> lists, int number ) {
return lists.Any(l=>l.Any(x=>x == number))
}
}
Which can be rewritten in more generic way using IComparable interface
public static class ListOfListExtention {
public static bool ContainAny<T>
(this List<List<int>> lists, int value ) where T : IComparable<T> {
return lists.Any(l=>l.Any(x=>x == value))
}
}
So to compare with accepted answer, why wrap List in new class if you can just have one extension method.
I'm building some stuff out using Attributes. One thing I'd really like to implement as an attribute is a convert a string to this property's type using this function. Right now, I have this:
public delegate object ParameterConverter(string val);
[AttributeUsage(AttributeTargets.Property)]
public class ParameterConverterAttribute : ParameterBaseAttribute
{
ParameterConverter Converter;
public ParameterConverterAttribute(ParameterConverter converter)
{
Converter=converter;
}
public object Convert(string val)
{
return Converter(val);
}
}
And I use it like so:
public class Tester
{
[ParameterConverter(new ParameterConverter(TestConverter)] //error here
public int Foo{get;set;}
static object TestConverter(string val)
{
return 10;
}
}
However, .Net or at least C# doesn't appear to support this kind of thing. It appears that delegates inside of attributes doesn't work.
Is there any workarounds to this issue or a good way to deal with this problem?
No Delegates cannot be passed as an argument to an Attribute. The Supported types are :
Object
Type
Enum
Single Dimentional Array
bool, byte, float char, double, int, long, string .... etc.
But as it supports Type as well as strings, you can pass a Type and the name of the method to create a delegate inside the Attribute class.
public delegate object ParameterConverter(string val);
[AttributeUsage(AttributeTargets.Property)]
public class ParameterConverterAttribute : ParameterBaseAttribute
{
public ParameterConverter Converter { get; set; }
public ParameterConverterAttribute(Type delegateType, string method)
{
try{ // Important as GetMethod can throw error exception or return null
this.Converter = (ParameterConverter)Delegate.CreateDelegate(delegateType, delegateType.GetMethod(method));
}
catch { }
}
public object Convert(string val)
{
if(this.Converter != null)
return Converter(val);
}
}
And now you can use it like :
public class Tester
{
[ParameterConverter(typeof(ParameterConverter), "TestConverter"]
public int Foo{get;set;}
static object TestConverter(string val)
{
return 10;
}
}
I hope this would help you.
Lookup for TypeConverter class
or
Type Converter Example
This example shows how to create a type converter named AuthorConverter....The AuthorConverter example converts an Author object to a String and a String representation to an Author object.
UPDATE:
You can skip the limitations of attributes like #abhishek has shown.
Possible another way is to define some "convention over configuration": converter function is a method defined like so
private static Converter(string val) defined inside same class. In your case:
public class Tester
{
public int Foo{get;set;}
private static int FooConverter(string val)
{
return 10;
}
}
You can put some ParameterConverterAttribute on top of the property as a sign that custom converter function exists, but is not mandatory.
I have the following class and extension class (for this example):
public class Person<T>
{
public T Value { get; set; }
}
public static class PersonExt
{
public static void Process<TResult>(this Person<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
I was expecting I could write something like the following and it would work, but it doesn't:
var x = new Person<List<String>>();
x.Process();
Since List is lower in the inheritance tree than IEnumerable, shouldn't this be valid? It works if I new up a Person<IEnumerable<String>> of course because that's the direct type.
I'm trying to use an extension method that can be applied to all Person<T>'s as long as T implements IEnumerable<Something> because I need to use the .Any() method.
EDIT: Maybe my understanding of covariance is off? I know IEnumerable<String> should convert to IEnumerable<Object>, but couldn't IList<String> convert to IEnumerable<String>?
EDIT2: Forgot to mention that I am using .net 4.0.
I know IEnumerable<String> should
convert to IEnumerable<Object>, but
couldn't IList<String> convert to
IEnumerable<String>?
IList<String> can convert to IEnumerable<String>. The problem is that you're trying to convert Person<List<String>> to Person<IEnumerable<String>>, which is illegal. For example, it's perfectly valid to write:
var x = new Person<IEnumerable<String>>();
x.Value = new string[0];
since Value is of type IEnumerable<String> and a string array is an IEnumerable<String>. However, you cannot write:
var x = new Person<List<String>>();
x.Value = new string[0];
since Value is of type List<String>. Since you can't use a Person<List<String>> in all places where you could use a Person<IEnumerable<String>>, it's not a legal cast.
Note that you can do something similar to what you want if you add a second type parameter to your extension method:
public static void Process<TResult, TList>(this Person<TList> p)
where TList : IEnumerable<TResult>
{
Console.WriteLine(p.Value.Any());
}
Unfortunately, the compiler won't be able to infer both type parameters, so you would have to call it like this:
var x = new Person<List<String>>();
x.Process<String, List<String>>();
If you are using C# 4.0 and can use covariance, then you can define a covariant interface for person:
public interface IPerson<out T>
{
T Value { get; }
}
public class Person<T>
: IPerson<T>
{
public T Value { get; set; }
}
And then write your extension method as:
public static void Process<TResult>(this IPerson<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
Since IPerson<T>.Value is read-only, a IPerson<List<String>> can be used everywhere that an IPerson<IEnumerable<String>> can be, and the conversion is valid.
I'm not sure you've quite grasped the correct use of generics. In any event ...
The only thing that is incorrect is your declaration of extension method, and the way you are attempting to constrain the extension method.
public static class ThingExtensions
{
public static void Process<T>(this Thing<T> p)
where T : IEnumerable<string>
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
All I've really done is rename Person to Thing so that we're not getting hung up on what a Person<List<string>> really is.
public class Thing<T>
{
public T Value { get; set; }
}
class ListOfString : List<string>
{ }
class Program
{
static void Main(string[] args)
{
var x = new Thing<ListOfString>();
x.Value = new ListOfString();
x.Process();
x.Value.Add("asd");
x.Process();
var x2 = new Thing<int>();
// Error 1 The type 'int' cannot be used as type parameter 'T'
// in the generic type or method
// 'ThingExtensions.Process<T>(Thing<T>)'.
// There is no boxing conversion from 'int' to
// 'System.Collections.Generic.IEnumerable<string>'.
//x2.Process();
Console.Read();
}
}
You could also move the generic constraint to the Thing<T> if that was more applicable.
You mention covariance, but don't actually use it. You have to specify in or out on your generic parameters. Note that co/contravariance doesn't work on class types; they must be applied to interfaces.
So, introducing an interface and making it covariant:
public interface IPerson<out T>
{
T Value { get; }
}
public class Person<T> : IPerson<T>
{
public T Value { get; set; }
}
public static class PersonExt
{
public static void Process<TResult>(this IPerson<IEnumerable<TResult>> p)
{
// Do something with .Any().
Console.WriteLine(p.Value.Any());
}
}
allows this code to compile:
var x = new Person<List<String>>();
x.Process();